Search code examples
javascriptreactjsflowtypereact-css-modules

Using Flowtype with react-css-modules decorated components


Below is a simple component for showing error messages:

// @flow
import styles from 'styles/components/Error';
import React from 'react';
import CSSModules from 'react-css-modules';

type Props = {
  message: string
}

const Error = ({ message }: Props) => {
  return (
    <div styleName="error">
      {message}
    </div>
  );
};

export default CSSModules(Error, styles);

Note that it requires message property. Now if I use this component somewhere:

<Error />;

Flowtype should warn me that Error is missing required property message but it does not. If I do not wrap my Error component with react-css-modules, Flowtype does work as expected.

I'm thinking that I need to declare a type for Flowtype for it to understand wrapped components but my Google-fu did not yield any results.

What I did found:


Solution

  • This has been recently discussed on GitHub. Here's the relevant issue: https://github.com/facebook/flow/issues/2536

    In short, the problem is that Flow does not have any type information for the CSSModules function, so the return type is inferred as any.

    In other words:

    export default Error; // the type of this export is (_: P) => ?React$element<any>
    export default CSSModules(Error, styles); // the type of this export is any
    

    Long story short, you can provide your own type definition. I'll paste here the one suggested by @gcanti in the original issue:

    declare module 'react-css-modules' {
    
      declare type CssOptions = {
        allowMultiple?: boolean,
        errorWhenNotFound?: boolean,
      };
    
      declare type FunctionComponent<P> = (props: P) => ?React$Element<any>;
      declare type ClassComponent<D, P, S> = Class<React$Component<D, P, S>>;
    
      declare function exports<D, P, S, C: ClassComponent<D, P, S> | FunctionComponent<P>>(reactClass: C, styles: Object, cssOptions?: CssOptions): C;
    }
    

    Save the above in decls/react-css-modules.js or something similar and then configure your .flowconfig like:

    [libs]
    decls/.js
    

    This will preserve the type information when wrapping a component into CSSModules and allow flow to catch the intended errors.