ReactElementとReactNodeの違い
JSX.IntrinsicElements
まず、本題に入る前にJSX.IntrinsicElements
について抑えておく。
しかしこれについて理解するには、ReactではなくTypeScriptのドキュメントを読む必要がある。
要はJSXやTypeScriptがJSXをどう扱うかを知らないといけない。
まず、JSX式<expr />
で作られる要素には2つの場合が存在する。
intrinsic elements
value-based elements
intrinsic elements
これは<html>
や<div>
などの組み込み要素のこと…と言い切ってしまうのは少々乱暴。
厳密に言うなら、「TypeScriptが組み込み要素として認識する要素」のことを指していると考えられる。
なぜなら、HTMLの仕様書で定義されていないような非組み込み要素であっても、以下のようにして組み込み要素であるかのようにTypeScriptに認識させることができるからだ。
この例では、TypeScriptはfoo
という要素が組み込み要素であると認識している。
視点を変えれば、TypeScriptはJSX.IntrinsicElements
という型を調べて、<expr />
が組み込み要素であるかを判断していると考えられる。
という前提で@types/react
に書かれているJSX.IntrinsicElements
の型定義を見てみると「なるほど!」となる。
value-based elements
こちらに関しては、先述のintrinsic elementsの説明における表現を借りれば、「ユーザーが定義した要素であるとTypeScriptが認識した要素」を指す。
React.ReactNode
とReact.ReactElement
この前提をおさえて本題に入る。
React.ReactNode
とReact.ReactElement
はそれぞれどういう概念なのだろう?
Reactのドキュメントによると、まずReact.ReactNode
は以下のように定義されている。
- や createElement(‘div’) のようにして作成された React 要素
- createPortal で作成されたポータル
- 文字列
- 数値
- true, false, null, undefined(これらは表示されません)
- 他の React ノードの配列
定義が分かったところでReact.ReactNode
型は何を表現する集合なのだろう?
その答えは型定義に書いていた。
これらの型定義によると以下のことがわかる。
React.ReactElement
はJSXで表現される要素の集合である。React.ReactNode
はReactがレンダーできる物の集合である。React.ReactElement
はReact.ReactNode
の部分集合である。
React.ReactNode
についてはある程度理解できた。
一方でReact.ReactElement
はまだしっくり来てない。
React.ReactElement
って一体なんなのか?それを理解するためには、どうやら同時にJSX.Element
についても理解する必要があるらしい。
まず、JSX.Element
の型定義を見る。
つまり、JSX.Element
はReact.ReactElement
のサブタイプであることがわかる。
ここで、冒頭のTypeScriptのドキュメントのJSXのページに戻るとこんな事が書いてある。
Function Component As the name suggests, the component is defined as a JavaScript function where its first argument is a props object. TS enforces that its return type must be assignable to JSX.Element.
つまり、JSX.Element
という型は関数コンポーネントの戻り値を表現する型であることが分かる。
また、React.createElement()
の型定義も見てみる。返り値がReact.ReactElement
型であることがわかる。
うーん…今度はJSX.Element
については分かったけど、React.ReactElement
についてはまだしっくり来てない。