In this post, I'm going to discuss why and how to use TypeScript to type React components.
You'll find how to annotate component props, mark a prop optional, and indicate the return type.
1. Why typing React components?
TypeScript is useful if you're coding middle and bigger size web applications. Annotating variables, objects, and functions creates contracts between different parts of your application.
For example, let's say I am the author of a component that displays a formatted date on the screen.
interface FormatDateProps {
date: Date
}
function FormatDate({ date }: FormatDateProps): JSX.Element {
return <div>{date.toLocaleString()}</div>;
}
According to the FormatDateProps
interface, the component FormatDate
accepts the date
prop as an instance of Date
. This constraint is crucial because the FormatDate
component uses the date.toLocaleString()
method, which only works with date instances.
Now, the user of the FormatDate
component must satisfy this constraint:
<FormatDate date={new Date()} />
If the user passes a string to date
instead:
<FormatDate date="Sep 28 2021" />
TypeScript will show a type error, ensuring you catch this issue during development.
2. Typing props
One of the best benefits React gains from TypeScript is prop typing.
Typing a React component is typically a 2-step process:
A) Define the interface that describes the component props.
B) Annotate the props parameter in the functional component.
For example:
interface MessageProps {
text: string;
important: boolean;
}
function Message({ text, important }: MessageProps) {
return (
<div>
{important ? 'Important message: ' : 'Regular message: '}
{text}
</div>
);
}
Now, when rendering Message
, props must match the defined types:
<Message text="The form has been submitted!" important={false} />
2.1 Props validation
If you provide incorrect props, TypeScript will show a type error during development:
<Message text="The form has been submitted!" important={0} />
2.2 children prop
The children
prop holds the content between the opening and closing tags of a component:
<Component>children</Component>
To type the children
prop:
interface MessageProps {
children: JSX.Element | JSX.Element[];
important: boolean;
}
function Message({ children, important }: MessageProps) {
return (
<div>
{important ? 'Important message: ' : 'Regular message: '}
{children}
</div>
);
}
You can now pass children like so:
<Message important={false}>
<span>The form has been submitted!</span>
</Message>
or with multiple elements:
<Message important={false}>
<span>The form has been submitted!</span>
<span>Your request will be processed.</span>
</Message>
Challenge: How would you update the MessageProps
interface to also support a string value as a child?
2.3 Optional props
To make a prop optional, use ?
:
interface MessageProps {
children: JSX.Element | JSX.Element[];
important?: boolean;
}
function Message({ children, important = false }: MessageProps) {
return (
<div>
{important ? 'Important message: ' : 'Regular message: '}
{children}
</div>
);
}
Now you can skip the important
prop:
<Message>
<span>The form has been submitted!</span>
</Message>
3. Return type
TypeScript can infer the return type of a React functional component, which is usually JSX.Element
:
function Message({ children, important = false }: MessageProps): JSX.Element {
return (
<div>
{important ? 'Important message: ' : 'Regular message: '}
{children}
</div>
);
}
If the component may return null
, use JSX.Element | null
:
function ShowText({ show, text }: { show: boolean, text: string }): JSX.Element | null {
return show ? <div>{text}</div> : null;
}
3.1 Tip: enforce the return type
It's recommended to explicitly set the return type:
function BrokenComponent(): JSX.Element {
return
<div>Hello!</div>; // Error caught!
}
Feel free to comment below if you have any thoughts or questions!
Top comments (8)
btw you can do something like this
Or
The problem with React.FC is that it is impossible to use generic types like:
but i like the arrow functions though , that will make me sad hahaha
cool
Storybook's a great resource for this!
question did you try to make a markdown editor before ?
Nice post :D
Some comments may only be visible to logged-in visitors. Sign in to view all comments.