-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DefaultProps are not handled by higher-order components #4644
Comments
This is an interesting example. In your example, I can get the expected output by changing the return type of your component:
Note that I changed the return type to However, we can't generalize this approach to an arbitrary component, because we need to know both the default props type and the props type to derive the config type. cc @calebmer |
Is there any utility type we can use to automatically generate the "config" type without hardcoding it into the HOC definition? Have you ever considered making Props for ES6 class components match the "config" type definition? (in the past it worked like that for stateless functional components by using default function parameters)
|
This is how I got it to work: /* @flow */
import * as React from 'react';
// taken from https://github.com/digiaonline/react-flow-types
export type ComponentWithDefaultProps<DefaultProps: {}, Props: {}> =
React.ComponentType<Props> & {defaultProps: DefaultProps};
/**
* Here is a generic type for HOCs:
*
* It takes two type parameters: RequiredProps and ProvidedProps
*
* RequiredProps: The final wrapped component will need RequiredProps, in addition to its own props
* ProvidedProps: The final wrapped component will not need ProvidedProps, because the HOC will provide them to the inner component
*/
export type HigherOrderComponent<RequiredProps: {}, ProvidedProps: {}> =
& (<OriginalProps, DefaultProps>(component: ComponentWithDefaultProps<DefaultProps, OriginalProps>) =>
React.ComponentType<RequiredProps & $Diff<$Diff<OriginalProps, ProvidedProps>, DefaultProps>>)
& (<OriginalProps>(component: React.ComponentType<OriginalProps>) => React.ComponentType<RequiredProps & $Diff<OriginalProps, ProvidedProps>>);
type Props = { a: number, b: number };
class A extends React.Component<Props> {
static defaultProps = { a: 1 };
render() {
return <div />
}
}
// Pseudo-HOC that just passes the component through
const pseudoHoc: HigherOrderComponent<{}, {}> = (Component: any): any => {
return (props) => <Component {...props} />;
}
<A b={10} />; // No errors, as expected
<A a={10} b={10} />; // No errors, as expected
<A a="some string" b={10} />; // Errors as expected
const B = pseudoHoc(A);
// correctly errors
<B b={10} />; // No errors, as expected
<B a={10} b={10} />; // No errors, as expected
<B a="some string" b={10} />; // Errors as expected |
Has anyone found a more concise solution? That's an enormous amount of code to write just to get basic, default behavior. |
I think it would be a good idea if flow provided a generic However, @rsolomo, the |
This is something that breaks incremental adoption of flow. I've used @AriaMinaei's HOC and it works fantastically for anything that is fully flow typed! Thanks @AriaMinaei - it exposed > 1700 errors on a codebase that was previously zero! BUT I now have a big problem, because it seems this HOC pattern assumes everything is flow typed. So at least half of those errors were lingering legacy prop-types in the e.g.
The point it breaks in 122 declare type React$StatelessFunctionalComponent<Props> = {
123 (props: Props, context: any): React$Node,
124 displayName?: ?string,
125 propTypes?: $Subtype<{[_: $Keys<Props>]: any}>,
126 contextTypes?: any
127 }; This is a case where the a flow typed HOC wraps an old props-type component: This breaks incremental adoption of flow. So while I continue to use this in the library and I'll simply convert the rest of our legacy files, I worry a bit about our flow shadow files breaking users of the library when they have not fully adopted flow. |
The issue we've run into with workarounds like what @AriaMinaei proposed above is that there doesn't appear to be a way to do the right thing when props is an exact object type. Either you use |
The docs cover how to solve this issue now using React.ElementConfig: https://flow.org/en/docs/react/hoc/#toc-supporting-defaultprops-with-react-elementconfig |
I believe this is solved from Flow v0.89 with the new |
If a component has some non-optional
props
that are covered bydefaultProps
and is then wrapped by a HOC, thedefaultProps
are not used correctly on the wrapped component. Flow will instead produceProperty not found
errors.Version: 0.53.1
flow.org/try test case
The text was updated successfully, but these errors were encountered: