react-pdf icon indicating copy to clipboard operation
react-pdf copied to clipboard

Throwing Error in React 18

Open jagadeesh93 opened this issue 2 years ago • 13 comments

Describe the bug Using the package in react 18 is giving the error of children not mentioned in the props

To Reproduce Steps to reproduce the behavior including code snippet (if applies):

  1. Create a Sample File using React 18
  2. Try to Run the app
  3. See error

'(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>'.ts(2769) @diegomura

I belive in react 18 you need to explicitly define the children props https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html

jagadeesh93 avatar Apr 11 '22 09:04 jagadeesh93

same issue here, how do you solved it with child props? or is it still ongoing?

RiJung avatar Apr 11 '22 09:04 RiJung

same issue here, how do you solved it with child props? or is it still ongoing?

Its still ongoing , i am trying every possible way to at least patch it, so it can work until a proper fix is out , Will post if i found anything

jagadeesh93 avatar Apr 11 '22 09:04 jagadeesh93

if you want to use React18 , i use my little dirty helper this work, renaming helps to trick Typescript

import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer';

// rename helper for react18 overload
const MyDocument: any = Document
const MyPage: any = Page

// example code
const PDF= () => (
  <MyDocument>
    <MyPage="A4" style={styles.page}>
      <View style={styles.section}>
        <Text>Section #1</Text>
      </View>
      <View style={styles.section}>
        <Text>Section #2</Text>
      </View>
    </MyPage>
  </MyDocument>

RiJung avatar Apr 11 '22 10:04 RiJung

if you want to use React18 , i use my little dirty helper this work, renaming helps to trick Typescript

// rename helper for react18 overload
const MyDocument: any = Document
const MyPage: any = Page

// example code
const PDF= () => (
  <MyDocument>
    <MyPage="A4" style={styles.page}>
      <View style={styles.section}>
        <Text>Section #1</Text>
      </View>
      <View style={styles.section}>
        <Text>Section #2</Text>
      </View>
    </MyPage>
  </MyDocument>

Thank you very much , for the code

jagadeesh93 avatar Apr 11 '22 10:04 jagadeesh93

I faced the same problem with react 17, the solution presented by @RiJung is definitely super, here is an enhancement that does not lose the type checking as much as possible

import {
	Document as PdfDocument,
	Page as PdfPage,
	Text,
	View
} from '@react-pdf/renderer';
import React, {
	ClassType,
	Component,
	ComponentClass,
	ComponentProps,
	HTMLProps,
	ReactNode
} from 'react';

// I renamed `Page` to `PdfPage` on import, and here assigning itto a variable named `Page`
// so that the code here is aligned with `react-pdf` documentation examples,
// same goes with `Document` import.
const Page: ClassType<
  ComponentProps<typeof PdfPage> & { children?: ReactNode },
  Component<ComponentProps<typeof PdfPage> & { children?: ReactNode }>,
  ComponentClass<ComponentProps<typeof PdfPage> & { children?: ReactNode }>
> = PdfPage as any;

const Document: ClassType<
  ComponentProps<typeof PdfDocument> & {
    children: ReactNode;
  },
  Component<
    ComponentProps<typeof PdfDocument> & {
      children: ReactNode;
    }
  >,
  ComponentClass<
    ComponentProps<typeof PdfDocument> & {
      children: ReactNode;
    }
  >
> = PdfDocument as any;

export function Pdf(props: HTMLProps<HTMLDivElement>) {
  return (
    <Document>
      <Page size="A4" style={styles.page}>
        <View style={styles.section}>
          <Text>Section #1</Text>
        </View>
        <View style={styles.section}>
          <Text>Section #2</Text>
        </View>
      </Page>
    </Document>
  );
}

hahouari avatar Apr 11 '22 18:04 hahouari

Thanks for the workaround @RiJung Is there though a proper solution for this other than waiting for a new version of react-pdf? Will this be resolved in a future update?

kickbk avatar Apr 11 '22 19:04 kickbk

I still have issues with ReactPDF.Styles. "TS2559 Type string has not properites in common with type 'Style'" - But the workaround seems to work for the moment. (thx a lot hahouari)

Somehow there was/is also a change in ReactPDF.Styles so that this is not working anymore export const styles = StyleSheet.create({ ... But thats probably because of the uprade and I'll take a look at it tomorrow.

goot1 avatar Apr 11 '22 20:04 goot1

While waiting for an update. This should be a nicer solution to preserve TS definitions:

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>
)

Then you can keep using Document, Page, Svg, and possibly other react components that until react 18 used an implicit children prop.

kickbk avatar Apr 11 '22 20:04 kickbk

Here is some info on the @types/react 18 upgrade and the breaking change related to the children prop:

https://solverfox.dev/writing/no-implicit-children/

hcharley avatar Apr 12 '22 01:04 hcharley

if you want to use React18 , i use my little dirty helper this work, renaming helps to trick Typescript

import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer';

// rename helper for react18 overload
const MyDocument: any = Document
const MyPage: any = Page

// example code
const PDF= () => (
  <MyDocument>
    <MyPage="A4" style={styles.page}>
      <View style={styles.section}>
        <Text>Section #1</Text>
      </View>
      <View style={styles.section}>
        <Text>Section #2</Text>
      </View>
    </MyPage>
  </MyDocument>

this worked like a charm, thank you!

AbrahamTerfie avatar May 04 '22 01:05 AbrahamTerfie

Using the above workaround still ended up with an error in my project:

src/components/profile/download-pdf-modal/company-pdf/company-pdf.tsx:101:10 - error TS2352: Conversion of type 'ComponentType<Props>' to type 'ComponentType<Props & { children: ReactNode; }>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type 'FunctionComponent<Props>' is not comparable to type 'ComponentType<Props & { children: ReactNode; }>'.
    Type 'FunctionComponent<Props>' is not comparable to type 'FunctionComponent<Props & { children: ReactNode; }>'.
      Types of property 'propTypes' are incompatible.
        Type 'WeakValidationMap<Props>' is not comparable to type 'WeakValidationMap<Props & { children: ReactNode; }>'.
          Type 'null extends Props[K] ? Validator<Props[K]> : undefined extends Props[K] ? Validator<Props[K]> : Validator<Props[K]>' is not comparable to type 'null extends (Props & { children: ReactNode; })[K] ? Validator<(Props & { children: ReactNode; })[K]> : undefined extends (Props & { children: ReactNode; })[K] ? Validator<...> : Validator<...>'.
            Type 'Validator<Props[K]> | (undefined extends Props[K] ? Validator<Props[K]> : Validator<Props[K]>)' is not comparable to type 'null extends (Props & { children: ReactNode; })[K] ? Validator<(Props & { children: ReactNode; })[K]> : undefined extends (Props & { children: ReactNode; })[K] ? Validator<...> : Validator<...>'.
              Type 'undefined extends Props[K] ? Validator<Props[K]> : Validator<Props[K]>' is not comparable to type 'null extends (Props & { children: ReactNode; })[K] ? Validator<(Props & { children: ReactNode; })[K]> : undefined extends (Props & { children: ReactNode; })[K] ? Validator<...> : Validator<...>'.
                Type 'Validator<Props[K]>' is not comparable to type 'null extends (Props & { children: ReactNode; })[K] ? Validator<(Props & { children: ReactNode; })[K]> : undefined extends (Props & { children: ReactNode; })[K] ? Validator<...> : Validator<...>'.

101   return Component as React.ComponentType<Props & { children: ReactNode }>;

We were able to fix it by changing the componentWithChildren function to this:

function componentWithChildren<Props>(Component: React.ComponentType<Props>) {
  return Component as unknown as React.ComponentType<
    Props & { children: ReactNode }
  >;
}

But this doesn't seem ideal, and I'm not sure why its working for others and not us. These are the package versions we're on:

"@react-pdf/renderer": "^2.1.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"@types/node": "^17.0.34",
"@types/react": "^18.0.9",
"typescript": "^4.6.4"

If anyone has any insight, I'm definitely curious.

csandman avatar May 17 '22 21:05 csandman

Does anyone know when it will be compatible with React 18?

Rafael805 avatar May 26 '22 16:05 Rafael805

Add those lines to a d.ts file fix the error for now :

declare module '@react-pdf/renderer' {
  export { Circle, G, Path } from '@react-pdf/renderer';

  export class Svg extends React.Component<React.PropsWithChildren<SVGProps>> {}
}

antoine-giret avatar Sep 06 '22 07:09 antoine-giret

should be fixed in v3.1.1

jeetiss avatar Jan 28 '23 16:01 jeetiss