これはなに?
Flow 0.82.0 で行われた React.Node 型の修正が面白かったのでメモ。
React render() cannot return undefined: React$Node shouldn't be undefined
https://github.com/facebook/flow/pull/6829
なぜ修正が必要か?
Flow には React が描画可能な型を表現する React.Node
という型が用意されています。
Flow 0.81.0 以前では React.Node 型は次のように定義されていました。
declare type React$Node =
| void
| null
| boolean
| number
| string
| React$Element<any>
| React$Portal
| Iterable<React$Node>;
今回問題となったのは void
が許可されているという点です。 Flow でいうところの void は JavaScript でいうところの undefined
を表します。
改めて React コンポーネントの render メソッドのドキュメントを見てみると、実は undefined
を返すことは許可されていません。実際に render メソッドで undefined
を返すと例外扱いとなります。
render() | React.Component – React
https://reactjs.org/docs/react-component.html#render
この挙動は JSX 内の JavaScript 式における undefined
と混同しやすいですが、JSX 内での JavaScript 式に undefined
を用いることは可能です。 undefined
を渡した場合、単に何も描画しないという挙動になります。
どう修正されたか?
この問題を受けて、Flow 0.82.0 で次のように修正されることになりました。
declare type React$Node =
- | void
| null
| boolean
| number
| string
| React$Element<any>
| React$Portal
- | Iterable<React$Node>;
+ | Iterable<?React$Node>;
props.children への影響
React コンポーネントの render メソッドの戻り値の型は React.Node
で正しく表現されるようになりました。React.Node
は props.children
の型としても利用されていたので、合わせて ?React.Node
という型に変更されています。
おわりに
今回の修正はリリースノートに言及がなかったので、 v0.81.0 と v0.82.0 の差分から推測しながら変更内容を把握しました。(悲しいかな Flow ではよくあるのでもう慣れてしまったが...)
細かい変更であっても積み重なると修正の難易度が上がってしまうことがあるので、 Flow のバージョンにはこまめに追従しておくほうが良いでしょう。
ちなみに 0.85.0 では、意図せず型を要求できていなかった箇所がたくさん見直されて、型の注釈を求めるようになっているので、しばらくバージョンアップをサボってる人は覚悟しておくように。