Chaim Leib Halbert
Chaim Leib Halbert

Reputation: 2324

Flow + React breaks when capitalizing stateless component

What works

I'm trying to write a stateless component. The following code works and flow says it's ok:

import React, { type Node } from 'react';

function renderCond({children}: {children: Array<[boolean, ?Node]>}): ?Node {
  for (const [bool, Component: ?Node] of children) {
    if (bool) {
      return Component;
    }
  }
  return null;
}

<renderCond>
  {[
    [false, <h1>{'Comp 1'}</h1>],
    [true, <h1>{'Comp 2'}</h1>],
    [true, <h1>{'Comp 3'}</h1>],
  ]}
</renderCond>

What doesn't

But, if I search and replace "renderCond" with "RenderCond", flow blows up. Why?

3: function RenderCond({children}: {children: Array<[boolean, ?Node]>}): ?Node {
                                                                         ^
all branches are incompatible: Either null or undefined [1] is incompatible with null [2]. Or property `@@iterator` is missing in null or undefined [1] but exists in `$Iterable` [3].

References:
3: function RenderCond({children}: {children: Array<[boolean, ?Node]>}): ?Node {
                                                                         ^ [1]
[LIB] ..//static/v0.93.0/flowlib/react.js:14:   | null
                                                  ^ [2]
[LIB] ..//static/v0.93.0/flowlib/react.js:20:   | Iterable<?React$Node>;
                                                  ^ [3]

It works if I return Component || null and don't use an optional return type, but I still don't understand why I have to do that. If an optional type is coming in, and I'm returning that optional thing out, why should flow complain that all branches are incompatible?

Even if I return Component || null without changing the return type, flow still errors.

flow listed more branches when I ran locally with flow --show-all-branches. Why was undefined not in the list?

TryFlow links

Upvotes: 0

Views: 83

Answers (2)

Jordan Brown
Jordan Brown

Reputation: 638

Function components must return a subtype of React$Node, which does not include void.

Upvotes: 0

Oluwafemi Sule
Oluwafemi Sule

Reputation: 38922

The flow system infers null differently when RenderCond component is written JSX style.

null is inferred to be an iterable React$Node and shouldn't be hinted as an optional return type.

RenderCond({children}: {children: Array<[boolean, ?Node]>}): Node {}

Upvotes: 0

Related Questions