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 DocumentNo 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.