React.FC
was removed from create-react-app in Jan 2020 due to two drawbacks, but with the release of TypeScript 5.1 and React 18, these issues have been resolved, allowing components to return various types without errors and improving type safety.
React.FC
received love and hate from the React community and at some point it was criticized enough to get itself removed from create-react-app back on Jan 23, 2020. But why?
Cannot type components returning
undefined
,string
ornumber
although it is a perfectly valid syntax.Implicitly includes children in props type
Now with the latest release of TypeScript 5.1 and React 18, it no longer displays those squiggly red lines.
What does that mean?
Let's take an example of a functional component that returns a string
,
const Greet: React.FC = () => {
return "Hello World"
};
before TypeScript 5.1 and React 18, this would throw an error as
Type '() => string' is not assignable to type 'FC<{}>'. Type 'string' is not assignable to type 'ReactElement<any, any>'.ts(2322)
But now with a newer version, this is a perfectly valid syntax.
Another example covering the 2nd drawback of React.FC
,
const Button: React.FC = () => {
return <button>Click me</button>;
};
export const App = () => {
<Button>Boop</Button>; // valid syntax
};
In the above example, the Button component does not accept children but TypeScript doesn't warn you if you try to provide children Boop
like <Button>Boop</Button>
Now with the newer versions, the above code would throw an error as
Type '{ children: string; }' has no properties in common with type 'IntrinsicAttributes'.ts(2559)
What changed?
Well, React fixed these typings by replacing the return type of React.FC
from React.ReactElemet
to React.ReactNode
What's the difference?
React.ReactElement
type is defined as,
interface ReactElement<
P = any,
T extends string | JSXElementConstructor<any> =
| string
| JSXElementConstructor<any>
> {
type: T;
props: P;
key: Key | null;
}
which means that it breaks when you attempt to pass in a string
, number
, or undefined
as a child.
Whereas React.ReactNode
is defined as a type that accepts all possible types that React can render.
type ReactNode =
| ReactChild
| ReactFragment
| ReactPortal
| boolean
| null
| undefined;
type ReactFragment = {} | Iterable<ReactNode>;
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
interface ReactPortal extends ReactElement {
key: Key | null;
children: ReactNode;
}
Conclusion
In conclusion, the latest TypeScript 5.1 and React 18 updates have addressed the issues with React.FC, allowing components to return various types such as strings, numbers, and undefined without errors. This improvement enhances the developer experience and ensures better type safety when using functional components in React applications.
Top comments (0)