Flow version: 0.82.0 and later
flow should report no errors with this function as input.
Deleting the JSX block makes flow report everything is fine. Restoring the JSX block, which calls the function as a stateless React component, makes flow error, and point at the function definition, instead of at its usage.
// @flow
import React, { type Node } from 'react';
function RenderCond({children}: {children: Array<[boolean, ?Node]>}): ?Node {
for (const [bool, Component] of children) { // ^ ERROR
if (bool) {
return Component;
}
}
return null;
}
// Try deleting this block:
<RenderCond>
{[
[false, <h1>{'Comp 1'}</h1>],
[true, <h1>{'Comp 2'}</h1>],
[true, <h1>{'Comp 3'}</h1>],
]}
</RenderCond>
The above produces the following error on flow versions after 0.81.0:
$ flow --show-all-branches
Error ┈┈┈┈ src/util/renderCond.js:3:71
All branches are incompatible:
• Either null or undefined [1] is incompatible with null [2].
• Or null or undefined [1] is incompatible with boolean [3].
• Or null or undefined [1] is incompatible with number [4].
• Or null or undefined [1] is incompatible with string [5].
• Or inexact null or undefined [1] is incompatible with exact React.Element [6].
• Or null or undefined [1] is incompatible with React.Portal [7].
• Or property @@iterator is missing in null or undefined [1] but exists in $Iterable [8].
src/util/renderCond.js
1│ // @flow
2│ import React, { type Node } from 'react';
[1] 3│ function RenderCond({children}: {children: Array<[boolean, ?Node]>}): ?Node {
4│ for (const [bool, Component] of children) { // ^ ERROR
5│ if (bool) {
6│ return Component;
/private/tmp/flow/flowlib_2060946e/react.js
[2] 14│ | null
[3] 15│ | boolean
[4] 16│ | number
[5] 17│ | string
[6] 18│ | React$Element<any>
[7] 19│ | React$Portal
[8] 20│ | Iterable<?React$Node>;
I believe Flow is correct here:
Without your usage in JSX, there's no way Flow could know your function is a React component. It could just be a general purpose function that happens to deal with React components as its inputs/outputs, in which case there's nothing wrong with it.
However, if you want it to be a React component, it needs to follow React standards. Which are that undefined is not a valid return type. You should just be using Node, which covers everything React can render, including null. By writing ?Node, you're making a union of Node | null | void (undefined).
Your Try Flow works if you replace all ?Node with Node.
@jamesisaac is spot on.
Most helpful comment
I believe Flow is correct here:
Without your usage in JSX, there's no way Flow could know your function is a React component. It could just be a general purpose function that happens to deal with React components as its inputs/outputs, in which case there's nothing wrong with it.
However, if you want it to be a React component, it needs to follow React standards. Which are that
undefinedis not a valid return type. You should just be usingNode, which covers everything React can render, includingnull. By writing?Node, you're making a union ofNode | null | void (undefined).Your Try Flow works if you replace all
?NodewithNode.