Different ways to strongly-type function component props with TypeScript
One of the most beneficial parts of using TypeScript with React is the ability to have strongly-typed component props. This allows developers using the component to quickly understand what they can pass and helps them avoid making a mistake.
In this post, we will go through several different approaches to strongly-typing a function component props. We are going to strongly-type the props for the following component:
const TextField = ({
label,
text,
onTextChange
}) => (
<div>
<label>{label}</label>
<input
type="text"
value={text}
onChange={e =>
onTextChange(e.currentTarget.value)
}
/>
</div>
);
Inline type annotation
Perhaps the simplest approach is to use an inline type annotation on the props
function parameter:
const TextField = ({
label,
text,
onTextChange
}: { label: string; text: string; onTextChange: (text: string) => void;}) => ...
This is a nice approach when there are only a couple of props in our component, and the props don’t need to be reused.
This can also be used if the component is a regular function rather than an arrow function:
function TextField({
label,
text,
onTextChange
}: { label: string, text: string, onTextChange: (text: string) => void}) { ...
}
Type alias
We could extract the props into a type alias:
type Props = { label: string; text: string; onTextChange: (text: string) => void;};const TextField = ({
label,
text,
onTextChange
}: Props) => ...
This is great when there are at least a few props, or we want to reuse the props type across multiple components.
Again, this approach can be used for regular function components:
function TextField({
label,
text,
onTextChange
}: Props) ...
Interface
We can use an interface instead of a type alias:
interface Props {
label: string;
text: string;
onTextChange: (text: string) => void;
}
Interfaces have very similar capabilities to type aliases these days, so it’s generally a personal preference for which to use.
FC
type
There is a standard React type, FC
, that we can use on arrow function components. “FC” stands for Function Component, and it aliases a type called FunctionComponent
.
const TextField: React.FC<Props> = ({ label,
text,
onTextChange
}) => ...
The FC
type is used on the variable assigned to the arrow function. It is a generic type that we pass the components props type into.
There are some arguable minor benefits to using the FC
type:
FC
provides some type safety ondefaultProps
, which can be used to provide default values for the props. However,defaultProps
may be removed from React in a future release.FC
includes thechildren
prop type, so you don’t have to define it explicitly. However, it is arguably better to explicitly define this so that consumers know for sure whether this is available.
Extending a standard type
The props type can extend a standard type:
interface Props
extends React.InputHTMLAttributes< HTMLInputElement > { label: string;
text: string;
onTextChange: (text: string) => void;
}
In the above example, we have extended the standard props type for an input
element. This means our component now accepts props such as maxLength
and placeholder
.
Alternatively we can use a type alias and intersection to achieve the same effect:
type Props = React.InputHTMLAttributes< HTMLInputElement> & { label: string;
text: string;
onTextChange: (text: string) => void;
};
If you to learn more about using TypeScript with React, you may find my course useful: