Reputation: 1014
I can't figure out how to correctly type a Wrapper and Counter component when using render props. I've tried the following but it just leads to more errors:
App.js
// @flow
const App = (): React.Node => {
return (
<div className="App">
<Wrapper render={(count, increment) => {
return <Counter1 count={count} increment={increment}/>
}}/>
<Wrapper render={(count, increment) => {
return <Counter2 count={count} increment={increment} />
}}/>
</div>
);
};
Wrapper.js
// @flow
import * as React from 'react';
type WrapperProps<T> = {
render: T => React.Node
};
export const Wrapper = <T>({render}): Props<T> => {
const [count, setCount] = React.useState<number>(0);
const increment = (prevCount: number) => setCount(count + 1);
return (
<div>
{render(count, increment)}
</div>
);
}
Counter1.js
// @flow
import * as React from 'react';
export const Counter1: React.Node = ({ count, increment }) => {
return (
<>
<div>Counter 1: {count}</div>
<button onClick={increment}>Increment</button>
</>
);
};
Counter2.js
// @flow
import * as React from 'react';
export const Counter2 = ({ count, increment }) => {
return (
<>
<div>Counter 2: {count}</div>
<button onClick={increment}>Increment</button>
</>
);
};
I currently have 14 errors and I'm really lost. I can't figure out how to type Wrapper props and counter props. Here are some of the errors:
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because $Iterable [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because React.Element [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because React.Portal [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because boolean [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because null [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because number [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Counter1.js:4:37
Cannot assign function to Counter1 because: [incompatible-type]
• Either inexact function [1] is incompatible with exact object type [2].
• Or function [1] is incompatible with React.Portal [3].
• Or property @@iterator is missing in function [1] but exists in $Iterable [4].
src/components/Counter1.js
1│ // @flow
2│ import * as React from 'react';
3│
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
5│ return (
6│ <>
7│ <div>Counter 1: {count}</div>
8│ <button onClick={increment}>Increment</button>
9│ </>
10│ );
11│ };
12│
/private/tmp/flow/flowlib_1fa18dde633e97c7_501/react.js
[2] 18│ | React$Element<any>
[3] 19│ | React$Portal
[4] 20│ | Iterable<?React$Node>;
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Counter2.js:4:26
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type
annotation at array pattern: [signature-verification-failure]
1│ // @flow
2│ import * as React from 'react';
3│
4│ export const Counter2 = ({ count, increment }) => {
5│ return (
6│ <>
7│ <div>Counter 2: {count}</div>
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Counter2.js:4:47
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type
annotation at function return: [signature-verification-failure]
1│ // @flow
2│ import * as React from 'react';
3│
4│ export const Counter2 = ({ count, increment }) => {
5│ return (
6│ <>
7│ <div>Counter 2: {count}</div>
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Wrapper.js:8:28
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type
annotation at array pattern: [signature-verification-failure]
5│ render: T => React.Node
6│ };
7│
8│ export const Wrapper = <T>({render}): Props<T> => {
9│ const [count, setCount] = React.useState<number>(0);
10│
11│ const increment = (prevCount: number) => setCount(count + 1);
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Wrapper.js:8:39
Cannot resolve name Props. [cannot-resolve-name]
5│ render: T => React.Node
6│ };
7│
8│ export const Wrapper = <T>({render}): Props<T> => {
9│ const [count, setCount] = React.useState<number>(0);
10│
11│ const increment = (prevCount: number) => setCount(count + 1);
Upvotes: 0
Views: 234
Reputation: 1335
Your first issue is related to the Counter1
component line
export const Counter1: React.Node = ({ count, increment }) => {
Which basically is typing Counter1 as a React.Node, what you really want is a function that RETURNS a React.Node like so
export const Counter1 = ({ count, increment }): React.Node => {
Your second issue related to Counter2
is related to types-first where every module export has to be explicitly typed so that flow can run at maximum performance, you can read more about it here.
And your last issue in the Wrapper
component is related to the fact that you have a type called WrapperProps
but you've used it as Props
so it's saying it can't find it. Also I believe you've placed your WrappedProps
in the wrong place, so change it from
export const Wrapper = <T>({render}): Props<T> => {
to
export const Wrapper = <T>({render}: Props<T>): React.Node => {
Though in retrospect you might want to think about how a parent component will actually consume this and pass in the generic, because your render func is already expecting two arguments so a generic is not very helpful here. Based on your code, you probably want something like this
type WrapperProps = {
render: (
number,
(number) => void,
) => React.Node,
};
export const Wrapper = ({render}: WrapperProps): React.Node => {
Upvotes: 1