artsy / fresnel

An SSR compatible approach to CSS media query based responsive layouts for React.
https://artsy.github.io/blog/2019/05/24/server-rendering-responsively
Other
1.24k stars 65 forks source link

Typescript issue in functional component #281

Closed filipizydorczyk closed 2 years ago

filipizydorczyk commented 2 years ago

Hello! I just started to use this library and immediately run into types issue. When i put this code

    const QueryBreakpoints = createMedia({
        // breakpoints values can be either strings or integers
        breakpoints: {
            sm: 0,
            md: 700,
        },
    });

    const MediaContextProvider = QueryBreakpoints.MediaContextProvider;
    const Media = QueryBreakpoints.Media;

And I try to use Media and MediaContextProvider as react elements in my functional component

(
  <MediaContextProvider>
    <Media at="sm">
      <MobileApp />
    </Media>
    <Media greaterThanOrEqual="md">
      <TabletApp />
    </Media>
  </MediaContextProvider>
)

I get this error messages

'Media' cannot be used as a JSX component.
  Its element type 'ReactElement<any, any> | Component<MediaProps<"sm" | "md", never>, any, any> | null' is not a valid JSX element.
    Type 'Component<MediaProps<"sm" | "md", never>, any, any>' is not assignable to type 'Element | ElementClass | null'.
      Type 'Component<MediaProps<"sm" | "md", never>, any, any>' is not assignable to type 'ElementClass'.
        The types returned by 'render()' are incompatible between these types.
          Type 'React.ReactNode' is not assignable to type 'import("/mnt/commondisk/filip/Development/personal/tmp-app/node_modules/react-bootstrap/node_modules/@types/react/index").ReactNode'.

and same error for provider

const MediaContextProvider: React.ComponentType<MediaContextProviderProps<"sm" | "md">>
'MediaContextProvider' cannot be used as a JSX component.
  Its element type 'ReactElement<any, any> | Component<MediaContextProviderProps<"sm" | "md">, any, any> | null' is not a valid JSX element.
    Type 'Component<MediaContextProviderProps<"sm" | "md">, any, any>' is not assignable to type 'Element | ElementClass | null'.
      Type 'Component<MediaContextProviderProps<"sm" | "md">, any, any>' is not assignable to type 'ElementClass'.
        The types returned by 'render()' are incompatible between these types.
          Type 'React.ReactNode' is not assignable to type 'import("/mnt/commondisk/filip/Development/personal/tmp-app/node_modules/react-bootstrap/node_modules/@types/react/index").ReactNode'.
            Type '{}' is not assignable to type 'ReactNode'.

I have no idea why its happening but I did manage to cheat typescript. I just wrote these asserions

    // workaround to fresnel type issue
    const MediaContextProvider =
        QueryBreakpoints.MediaContextProvider as unknown as React.FC;
    const Media = QueryBreakpoints.Media as unknown as React.FC<{
        at?: any;
        greaterThanOrEqual?: any;
    }>;

Then errors disapeared and I was able to run code and everything was working as expected. I belive there is a problem in types but maybe I am missing something?


IRelaxxx commented 2 years ago

I had the same problem. My solution was to downgrade @types/react and @types/react-dom to

    "@types/react": "17.0.47",
    "@types/react-dom": "17.0.17",
damassi commented 2 years ago

Unfortunately React 18 introduced a breaking change in TS where children is no longer available on FC. Will fix this now.

damassi commented 2 years ago

Fixed in https://github.com/artsy/fresnel/pull/287