React 元件型別定義的區別:JSX.Element vs ReactNode vs ReactElement
本文翻譯整理自 StackOverflow 問答 When to use JSX。Element vs ReactNode vs ReactElement?
元件型別定義
很多人可能在使用 TypeScript 編寫 React 應用的時候會對三種不同的函式返回值型別產生困惑,不明白它們之間的區別以及應該什麼時候使用哪一種型別才比較嚴謹。
ReactElement
是含有 props 和 type 屬性的物件:
type
Key
=
string
|
number
interface
ReactElement
<
P
=
any
,
T
extends
string
|
JSXElementConstructor
<
any
>
=
string
|
JSXElementConstructor
<
any
>>
{
type
:
T
;
props
:
P
;
key
:
Key
|
null
;
}
ReactNode
則是多種型別的集合:
type
ReactText
=
string
|
number
;
type
ReactChild
=
ReactElement
|
ReactText
;
interface
ReactNodeArray
extends
Array
<
ReactNode
>
{}
type
ReactFragment
=
{}
|
ReactNodeArray
;
type
ReactNode
=
ReactChild
|
ReactFragment
|
ReactPortal
|
boolean
|
null
|
undefined
;
類元件的 render 成員函式會返回 ReactNode 型別的值,而且 PropsWithChildren 型別中指定的 children 型別也是 ReactNode。
const
Comp
:
FunctionComponent
=
props
=>
<
div
>
{
props
。
children
}
<
/div>
// children?: React。ReactNode
type
PropsWithChildren
<
P
>
=
P
&
{
children?
:
ReactNode
;
}
雖然 React 的型別定義看起來寫得很複雜,但它實際上等價於:
type
ReactNode
=
{}
|
null
|
undefined
;
由於
{}
是所有物件的原型,你可以把幾乎任何型別賦值給 ReactNode,但絕大多數情況下應該對它進行更詳細的型別宣告。
JSX。Element
透過執行 React。createElement 或是轉譯 JSX 獲得。
const
jsx
=
<
div
>
hello
<
/div>
const
ele
=
React
。
createElement
(
“div”
,
null
,
“hello”
);
<
p
>
// <- ReactElement = JSX。Element
<
Custom
>
// <- ReactElement = JSX。Element
{
true
&&
“test”
}
// <- ReactNode
<
/Custom>
<
/p>
JSX 是一個全域性的名稱空間,不同的庫對 JSX 都可以有自己不同的實現,而 React 的實現方式就是讓
JSX.Element 等價於 ReactElement
,同時將它的泛型 props 和 type 都設為 any:
declare
global
{
namespace
JSX
{
interface
Element
extends
React
。
ReactElement
<
any
,
any
>
{
}
}
}
返回型別的不同
有的同學可能會注意到:類元件渲染方法的返回值型別和函式元件的是不一樣的,這是因為目前版本的 TypeScript 型別定義並不能準確地限定 React 實際值的範圍:
類元件型別定義
:透過 render() 返回 ReactNode,比 React 的實際值範圍更寬鬆
函式元件型別定義
:返回 JSX。Element,也比 React 的實際值範圍更寬鬆
實際上 React 類元件中的 render() 和函式元件的返回型別是一樣的,而 TypeScript 只是出於歷史原因和向後相容需要,為不同種類的元件聲明瞭不同的返回值型別。
根據 文件的規定 我們可以為元件返回值給出準確的型別定義:
type
ComponentReturnType
=
ReactElement
|
Array
<
ComponentReturnType
>
|
string
|
number
|
boolean
|
null
// 注意: 不能傳入 undefined