Flow: Injecting Props With a HOC does not work with functional stateless component

Created on 4 Mar 2018  路  7Comments  路  Source: facebook/flow

This code works on https://flow.org/try but does not work when MyEnhancedComponent is imported elsewhere.

import * as React from 'react';

function injectProp<Props: {}>(
  Component: React.ComponentType<Props>,
): React.ComponentType<$Diff<Props, { foo: number | void }>> {
  return function WrapperComponent(props: Props) {
    return <Component {...props} foo={42} />;
  };
}

// This works in flow.org/try but not if MyEnhancedComponent is imported from another file.
const MyComponent = (props: {a: number, b: number, foo: number}) => null;

// class MyComponent extends React.Component<{
//  a: number,
//  b: number,
//  foo: number,
// }> {}

const MyEnhancedComponent = injectProp(MyComponent);

// We don't need to pass in `foo` even though `MyComponent` requires it.
<MyEnhancedComponent a={1} b={2} />;

screen shot 2018-03-04 at 00 32 34

Most helpful comment

@steida does following work better:

function injectProp<Com: React.ComponentType<*>>(
  Component: Com,
): React.ComponentType<$Diff<React.ElementConfig<Com>, { foo: number | void }>> {
  return function WrapperComponent(props: React.ElementConfig<Com>) {
    return <Component {...props} foo={42} />;
  };
}

It's slightly unintuitive, but you should use either ElementProps or ElementConfig to retrieve the component props: https://flow.org/en/docs/react/types/#toc-react-elementconfig

All 7 comments

When I switched https://github.com/este/este to PureComponent (for another reason), Flow HOC example seems to work.

There must be something wrong about how Flow handles exported functional stateless components with Flow HOC example.

Test case. If I will rewrite https://github.com/este/este/blob/master/components/Auth.js component to functional stateless, then where Auth is imported, it does not work.

@steida does following work better:

function injectProp<Com: React.ComponentType<*>>(
  Component: Com,
): React.ComponentType<$Diff<React.ElementConfig<Com>, { foo: number | void }>> {
  return function WrapperComponent(props: React.ElementConfig<Com>) {
    return <Component {...props} foo={42} />;
  };
}

It's slightly unintuitive, but you should use either ElementProps or ElementConfig to retrieve the component props: https://flow.org/en/docs/react/types/#toc-react-elementconfig

@villesau Yep, this works! Thank you.
@calebmer How we can help with docs updating?

@villesau Btw, why no ElementProps by default? Is there any drawback?

@steida Normally you might not want to enforce passing default props to the connected component. ElementProps and ElementConfig are otherwise the same, but ElementConfig marks default props as optional.

It took me forever to learn that React.ComponentType does not (or is not supposed to?) work like you would expect it to work with props - I thought it's a bug too.

Btw, with Flow 0.72, we can not use * anymore. Because http://github.com/este/este is using PureComponent, I don't care.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cletusw picture cletusw  路  52Comments

Macil picture Macil  路  47Comments

vjpr picture vjpr  路  55Comments

Gozala picture Gozala  路  54Comments

sophiebits picture sophiebits  路  66Comments