The problem with React.FunctionComponent
Some time ago I was working on the project to migrate 4 different applications supported by one team to TypeScript. That was a new experience for me and I dived deep into new information, digging and exploring approaches and best practices.
At that moment (early 2019), one of the most comfortable and ‘stable’ approaches
was to use React.FunctionComponent
(React.FC
), which provides all you need
just out of the box. It controls the returned type, it controls the children
prop.
We used pure functions (almost no classes) in our UI codebase and the migration
was quite straight forward. This is a very basic example how you could use
FunctionComponent
.
import React from 'react';
interface Props {
extraText: string;
}
export const Component: React.FunctionComponent<Props> = props => (
<div>
<div>{props.children}</div>
<div>{props.extraText}</div>
</div>
);
That's really helpful interface, it helps a lot and covers many aspects of React components. It takes care of:
- defining
children
property - validating
defaultProps
interface - defining return type
Sometimes, I faced the situation where consumers tried to pass children to my
component, but I didn't expect them. In order to get type validation right, I
added children?: never
type to the interface. But that part is usually added
only after a failure happened. With this helpers it's really easy for me to stop
thinking about children
property at all.
Let's take a look how this component would look like without FunctionComponent
interface.
import React from 'react';
interface Props {
extraText: string;
children?: React.ReactNode;
}
export const Component = (props: Props) => (
<div>
<div>{props.children}</div>
<div>{props.extraText}</div>
</div>
);
I would like to highlight, that this snippet is safe even without specifying the
return type. I might use another component and would like to be type safe, in
this case I add return type to the arrow function, see the JSX.Element
part
below. Really, I don't want to get undefined
from AnotherComponent
and ruin
everything.
export const Component = (props: Props): JSX.Element => (
<AnotherComponent {/* ... */} />
);
That's totally fine until you want to use generic components. You can't do it
with React.FunctionComponent
unfortunately.