When using function components in React, we may want to type their props with TypeScript. Overall there are two ways of making a React component type safe with TypeScript, however, let's start by converting the following JavaScript React component to a TypeScript React component as leading example:
const Select = ({ label, value, options, onChange }) => {return (<label>{label}<select value={value} onChange={onChange}>{options.map((option) => (<option value={option.value}>{option.label}</option>))}</select></label>);};
The straightforward yet most verbose way of typing this React component would be inlining the types in the functional component's function signature:
const Select = ({label,value,options,onChange,}: {label: string;value: string;options: { label: string; value: string }[];onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;}) => {return (<label>{label}<select value={value} onChange={onChange}>{options.map((option) => (<option value={option.value}>{option.label}</option>))}</select></label>);};
From there, we would start extracting reusable types from the functional component's function signature into a standalone TypeScript type. It's up to you whether you prefer using a type or interface:
type Option = { label: string; value: string };type Options = Option[];const Select = ({label,value,options,onChange,}: {label: string;value: string;options: Options;onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;}) => {return (<label>{label}<select value={value} onChange={onChange}>{options.map((option) => (<option value={option.value}>{option.label}</option>))}</select></label>);};
Since React props are just a JavaScript object, we can extract a type respectively to the React function component's props too:
type Option = { label: string; value: string };type Options = Option[];type SelectProps = {label: string;value: string;options: Options;onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;};const Select = ({ label, value, options, onChange }: SelectProps) => {return (<label>{label}<select value={value} onChange={onChange}>{options.map((option) => (<option value={option.value}>{option.label}</option>))}</select></label>);};
In the beginning I mentioned that there are two ways of make a React component type safe. The last code snippet already showed you one way of doing it. A more popular way would be using TypeScript's type annotation syntax:
type Option = { label: string; value: string };type Options = Option[];type SelectProps = {label: string;value: string;options: Options;onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;};const Select: React.FC<SelectProps> = ({label,value,options,onChange,}) => {return (<label>{label}<select value={value} onChange={onChange}>{options.map((option) => (<option value={option.value}>{option.label}</option>))}</select></label>);};
After all, the syntax is up to you and your team. It would be important to align on one way of doing it though. Last but not least, you can also define a React component's return type even though it is usually inferred:
const Select: React.FC<SelectProps> = ({label,value,options,onChange,}): JSX.Element => {return (<label>{label}<select value={value} onChange={onChange}>{options.map((option) => (<option value={option.value}>{option.label}</option>))}</select></label>);};
That's it. You can make a function component's props type safe in TypeScript by using a type or interface. We have used the former here. In addition, you have two variations of defining types that I have presented here. Last but not least, you can optionally type a function component's return type.