Working around the removal of the children type from React.FC in React 18
One of the changes made in the release of React v18 was to remove the built-in children?: React.ReactNode
property from the React.FC
type.
Up until this point, many developers were used to writing components that might have looked something like this:
type MyComponentProps = {
style?: React.CSSProperties
}
const MyComponent : React.FC = ({ style, children }) => {
return (<div style={style}>{children</div>)
}
We’re able to do this because the children
property is built into React.FC
.
Upgrading to React v18, developers will need to add explicitly children?: React.ReactNode
to their type interface, for example:
type MyComponentProps = {
style?: React.CSSProperties
children?: React.ReactNode
}
const MyComponent : React.FC = ({ style, children }) => {
return (<div style={style}>{children</div>)
}
Easy enough!
Unfortunately, some libraries have not made this upgrade and still use React.FC
, which has the children
property is included. In my case, @recurly/react-recurly
had not been updated. This might not be a problem for everyone, but we needed to use yarn resolutions to ensure a consistent version react
and react-dom
are loaded throughout our monorepo.
{
"resolutions": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0"
}
}
Both components from Recurly’s library assume children
, which gives the following errors:
import { Elements, RecurlyProvider } from '@recurly/react-recurly'
<RecurlyProvider publicKey={import.meta.env.VITE_RECURLY_KEY}>
<Elements>
<MyComponent />
</Elements>
</RecurlyProvider>
Type '{ children: Element; publicKey: any; }' is not assignable to type 'IntrinsicAttributes & RecurlyOptions'.
Property 'children' does not exist on type 'IntrinsicAttributes & RecurlyOptions'.ts(2322)
Type '{ children: Element; }' has no properties in common with type 'IntrinsicAttributes & ElementsProps'.ts(2559)
To work around this, we can declare the react
module and force it to work like React v17.
import * as React from '@types/react';
declare module 'react' {
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P> | undefined;
contextTypes?: ValidationMap<any> | undefined;
defaultProps?: Partial<PropsWithChildren<P>> | undefined;
displayName?: string | undefined;
}
}
Now libraries that haven’t been updated will work as they used to, even if they are referencing the old version of the types.