Short answer:
If You want to go deeper with component types an improve TS compilation time (not code performance) - go with React.FC
If You prefer function notation, feel free to use it.
Anyway, compiled code will be the same.
Long answer
If You want to narrow component return types, You should use React.FC.
Let's start with simple example, partially taken from here:
import React from 'react'
type Props = {
label: string
}
function A() {
return <div>Child One</div>;
}
const B: React.FC<Props> = ({ label }) => {
return <div>{label}</div>;
};
/**
* Assume, You want to allow only children with particular props
* In our case - props of children should match Props type
*/
function Parent({
children
}: {
children: React.ReactElement<{ label: string }>[];
}) {
return (
<div>{
children.map((child) => (
<div key={child.props.label}>{child}</div>
))
}</div>
)
}
function App() {
/**
* There is no TS error and it is almost expected ))
*/
return <Parent children={[<A />, <B label={'hello'} />]} />;
}
So, we need to help TS to properly narrow App children types. Let's use native syntax for children instead JSX
// Please replace App in prev example with App2
function App2() {
return React.createElement(Parent, {
children: [
/**
* Here should be an error, because all
* children of Parent should have Props
*
* Why there is no error?
*
* Because TS can't figure out proper type from A component annotation
*/
React.createElement(A),
React.createElement(B, { label: 'd' })
]
});
}
To make it work, we just need to replace:
function A() {
return <div>Child One</div>;
}
with
const A: React.FC = () => {
return <div></div>;
};
And voi-la, we have an error Property 'label' is missing in type '{}' but required in type '{ label: string; }'
Full working exmaple:
import React from 'react'
type Props = {
label: string
}
const A: React.FC = () => {
return <div></div>;
};
const B: React.FC<Props> = ({ label }) => {
return <div>{label}</div>;
};
/**
* Assume, You want to allow only children with particular props
* In our case - props of children should match Props type
*/
function Parent({
children
}: {
children: React.ReactElement<{ label: string }>[];
}) {
return (
<div>{
children.map((child) => (
<div key={child.props.label}>{child}</div>
))
}</div>
)
}
function App2() {
return React.createElement(Parent, {
children: [
/**
* Here should be an error, because all
* children of Parent should have Props
*
* Why there is no error?
*
* Because TS can't figure out proper type from A component annotation
*/
React.createElement(A),
React.createElement(B, { label: 'd' })
]
});
}
I see, that I did not convinced You. Ok, I understand. Let's take a look on next example.
Assume, You want to return from one component some particular type of other component
import React from 'react'
function Two(){
return <div></div>
}
type Props = {
label: string;
}
type CustomReturn = React.ReactElement<Props>;
const MainButton: React.FC<Props> = (prop: Props): CustomReturn =>
React.createElement(Two); // no error, but should be
There is no error at all, despite the fact that I have defined explicitly return type.
Let's use React.FC:
import React from 'react'
const Two: React.FC = () => <div></div>
type Props = {
label: string;
}
type CustomReturn = React.ReactElement<Props>;
const MainButton: React.FC<Props> = (prop: Props): CustomReturn =>
React.createElement(Two); // Error, as it should be
With React.FC, TS was able to infer types.
React.FCyou get for example thechildren-prop in yourprops. This means that you have typings onprops.children, which can sometimes be useful.