React 18 drops the implicit children prop

Ben Kass
2 min readApr 11, 2022

--

React 18

If you, or one of your project dependencies recently upgraded react to v18, then you’re probably in for some Typescript surprises of style:

(alias) const Document: typeof ReactPDF.Document
import Document
No overload matches this call.
Overload 1 of 2, ‘(props: DocumentProps | Readonly<DocumentProps>): Document’, gave the following error.
Type ‘{ children: Element; }’ has no properties in common with type ‘IntrinsicAttributes & IntrinsicClassAttributes<Document> & Readonly<DocumentProps>’.
Overload 2 of 2, ‘(props: DocumentProps, context: any): Document’, gave the following error.
Type ‘{ children: Element; }’ has no properties in common with type ‘IntrinsicAttributes & IntrinsicClassAttributes<Document> & Readonly<DocumentProps>’.

With React 18, Functional Components (and possibly other components, such as React.Component) no longer have implicit children props.
Many libraries will need to catch up and release updates, but you very likely integrated this bad practice in your code as well. I know I did. If you ever had something like const MyComponent: React.FC<Props> = …then, you will want to change to const MyComponent = ({prop: MyProp, children: ReactNode})

But what if you are using a library that needs to release an update to address this and in the meantime you’re seeing horrific TS errors?

Take React-PDF as example. Until recently, I used it as follows:

import React, { ReactNode } from "react";
import {
Page,
Document,
} from "@react-pdf/renderer";
const Template = () => (
<Document>
<Page>
// Children go here
</Page>
</Document>
)

However, to overcome our problem, an elegant workaround is creating a component that accepts the children prop as follows:

import React, { ReactNode } from "react";
import {
Page as _Page,
Document as _Document,
} from "@react-pdf/renderer";
function componentWithChildren<Props>(Component: React.ComponentType<Props>) {
return Component as React.ComponentType<Props & { children: ReactNode }>;
}
const Document = componentWithChildren(_Document);
const Page = componentWithChildren(_Page);
const Template = () => (
<Document>
<Page>
// Children go here
</Page>
</Document>
)

This method can be applied to other such cases with your code and save you lots of grief.

--

--

Ben Kass
Ben Kass

Written by Ben Kass

React native, Expo, and Firebase enthusiast

No responses yet