Using Flow 0.58+, React and react-router-dom, what is the correct way of defining props children of a component that is wrapped with withRouter?
Currently, I have a strange behaviour that I would like to understand when trying to specifying the type of a component's children that is wrapped with withRouter.
Let's assume a RouterAware component:
import React, { type Node } from 'react';
import { withRouter } from 'react-router-dom';
type Props = {
children: Node
};
const RouterAware = (props: Props) => <div>{props.children}</div>;
export default withRouter(RouterAware);
This component is then used like this:
const Root = () => (
<RouterAware>
<div>One</div>
<div>Two</div>
</RouterAware>
);
However, this gives 8 Flow errors, one for each of the 8 union types defined for React.Node:
declare type React$Node =
| void
| null
| boolean
| number
| string
| React$Element<any>
| React$Portal
| Iterable<React$Node>;
Error template is:
Error: src/js/Components/RouterAware.js:8
8: const RouterAware = (props: Props) => <div>{props.children}</div>;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function. This type is incompatible with
137: | React$StatelessFunctionalComponent<Props>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ object type. See lib: /private/tmp/flow/flowlib_116f8cac/react.js:137
Callable property is incompatible:
8: const RouterAware = (props: Props) => <div>{props.children}</div>;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function. This type is incompatible with
122: (props: Props, context: any): React$Node,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function type. See lib: /private/tmp/flow/flowlib_116f8cac/react.js:122
This parameter is incompatible:
8: const RouterAware = (props: Props) => <div>{props.children}</div>;
^^^^^ object type. This type is incompatible with
144: Component: React$ComponentType<{| ...ContextRouter, ...P |}>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ object type. See lib: ../../../flow-typed/npm/react-router-dom_v4.x.x.js:144
Property `children` is incompatible:
5: children: Node
^^^^ <Specific union type here>. This type is incompatible with
35: <RouterAware>
^^^^^^^^^^^^^ React children array. See: src/js/Root.js:35
Those flow errors are fixable by changing the children: Node definition to children: Node[].
However, this seems wrong at first sight and might even be a problem with react-router-dom definition. I say this because without the withRouter wrapping call, the definition works as expected using simply children: Node, having one or multiple children.
To add to the confusion/problem, now if the component is called using a single child:
const Root = () => (
<RouterAware>
<div>One</div>
</RouterAware>
);
The flow error is on children: Node[] with message div, The type is incompatible with object type array.
Is this the expected behaviour that when using withRouter, one should define its children props as being Node[] (even if it makes little sense since I would need children: Node | Node[] to handle both cases).
Or is this a bug? I think it's related to the how React components might turns children into either an array when multiple props.children=[<div>,<div>] or a single element when single props.children=<div>.
But even there, why it's only showing up with withRouter. Any explanation would be appreciate.