babel-plugin-flow-react-proptypes icon indicating copy to clipboard operation
babel-plugin-flow-react-proptypes copied to clipboard

Support `React.ElementProps`

Open rsolomon opened this issue 7 years ago • 5 comments

Flow provides a method for obtaining a component's prop types called React.ElementProps (documentation here).

babel-plugin-flow-react-proptypes does not recognize usage, resulting in a transpilation error along these lines:

ERROR in <COMPONENT_PATH>
Module build failed: TypeError: <COMPONENT_PATH>: Cannot read property 'forEach' of undefined
    at convertToPropTypes (/node_modules/babel-plugin-flow-react-proptypes/lib/convertToPropTypes.js:77:19)
    at /node_modules/babel-plugin-flow-react-proptypes/lib/convertToPropTypes.js:31:20
    at Array.forEach (<anonymous>)
    at convertToPropTypes (/node_modules/babel-plugin-flow-react-proptypes/lib/convertToPropTypes.js:27:21)
    at convertToPropTypes (/node_modules/babel-plugin-flow-react-proptypes/lib/convertToPropTypes.js:51:13)
    at /node_modules/babel-plugin-flow-react-proptypes/lib/convertToPropTypes.js:31:20
    at Array.forEach (<anonymous>)
    at convertToPropTypes (/node_modules/babel-plugin-flow-react-proptypes/lib/convertToPropTypes.js:27:21)
    at convertNodeToPropTypes (/node_modules/babel-plugin-flow-react-proptypes/lib/index.js:31:43)
    at PluginPass.TypeAlias (/node_modules/babel-plugin-flow-react-proptypes/lib/index.js:175:25)

rsolomon avatar Nov 29 '17 23:11 rsolomon

@rsolomon thanks for the report!

I'm not quite sure what we should do in this case. Could you give an example of how you're using this type in your code?

brigand avatar Nov 30 '17 02:11 brigand

For example, the material-ui library uses the withStyles HoC for most components. This HoC modifies the exported component's properties. For example:

https://github.com/mui-org/material-ui/blob/v1-beta/src/Menu/MenuItem.js

The component itself takes in Props and ProvidedProps, but the output only requires a diff of Props and DefaultProps. Using React.ElementProps<typeof MenuItem> would get the correctly diffed props, but using the exported Props would mean the user would incorrectly need to provide props that are already provided by either DefaultProps or ProvidedProps.

rsolomon avatar Nov 30 '17 02:11 rsolomon

@rsolomon does this look right?

Input:

import MenuItem from 'whatever';

type Props = {
  foo: React.ElementProps<typeof MenuItem>,
};
const C = (props: Props) => {};

Output:

import MenuItem from 'whatever';

const C = (props) => {};

C.propTypes = {
  foo: MenuItem.propTypes
    ? PropTypes.shape(MenuItem.propTypes).isRequired,
    : PropTypes.any.isRequired,
};

Are there other situations I'm missing?

brigand avatar Nov 30 '17 03:11 brigand

That's correct in that scenario, though usually I've been using the props for compositions. Ex:

import MenuItem from 'whatever';

type Props = React.ElementProps<typeof MenuItem> & {
  foo: string,
};
const C = (props: Props) => {};

With the expected output being:

import MenuItem from 'whatever';

const C = (props) => {};

C.propTypes = {
  ...MenuItem.propTypes,
  foo: PropTypes.string.isRequired,
};

rsolomon avatar Nov 30 '17 04:11 rsolomon

@rsolomon I implemented it for this case:

const React = require('react');
const MenuItem = require('./MenuItem');
type Props = {
  foo: React.ElementProps<typeof MenuItem>,
};
const C = (props: Props) => <div />;

Published as 9.2.0. I don't know when I'll have time to implement the intersection case. If you're interested in implementing this, a PR would be great!

If you take it on, you can use ./scripts/runOnFile example.js while developing.

brigand avatar Dec 01 '17 05:12 brigand