babel-plugin-flow-react-proptypes
babel-plugin-flow-react-proptypes copied to clipboard
Support `React.ElementProps`
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 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?
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 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?
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 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.