typescript 什么时候使用 JSX.Element、ReactNode 和 ReactElement?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/58123398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When to use JSX.Element vs ReactNode vs ReactElement?
提问by Golo Roden
I am currently migrating a React application to TypeScript. So far, this works pretty well, but I have a problem with the return types of my render
functions respectively my function components.
我目前正在将 React 应用程序迁移到 TypeScript。到目前为止,这工作得很好,但是我的render
函数的返回类型和我的函数组件有问题。
So far, I had always used JSX.Element
as return type, now this doesn't work any more if a component decides to notrender anything, i.e. return null
, since null
is no valid value for JSX.Element
. This was the beginning of my journey, because now I searched the web and found that you should use ReactNode
instead, which also includes null
and also a few other things that can happen. This seemed to be the better bet.
到目前为止,我一直用JSX.Element
的返回类型,现在这不工作了,如果一个组件决定不呈现任何东西,也就是回报null
,因为null
是没有有效的价值JSX.Element
。这是我旅程的开始,因为现在我搜索了网络,发现您应该使用ReactNode
它,其中还包括null
以及其他一些可能发生的事情。这似乎是更好的选择。
However, now when creating a function component, TypeScript complains about the ReactNode
type. Again, after some searching I found, that for function components you should use ReactElement
instead. However, if I do so, the compatibility issue is gone, but now TypeScript again complains about null
not being a valid value.
但是,现在在创建函数组件时,TypeScript 会抱怨ReactNode
类型。再次,经过一些搜索我发现,对于功能组件,您应该使用它ReactElement
。但是,如果我这样做,兼容性问题就消失了,但现在 TypeScript 再次抱怨null
不是有效值。
So, to cut a long story short, I have three questions:
所以,长话短说,我有三个问题:
- What is the difference between
JSX.Element
,ReactNode
andReactElement
? - Why do the
render
methods of class components returnReactNode
, but function components returnReactElement
? - How do I solve this with respect to
null
?
- 之间有什么区别
JSX.Element
,ReactNode
和ReactElement
? - 为什么
render
类组件的方法返回ReactNode
,而函数组件返回ReactElement
? - 我如何解决这个问题
null
?
回答by Jonas Wilms
What is the difference between JSX.Element, ReactNode and ReactElement?
JSX.Element、ReactNode 和 ReactElement 之间有什么区别?
A ReactElement is an object with a type and props.
ReactElement 是一个具有类型和道具的对象。
interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
type: T;
props: P;
key: Key | null;
}
A ReactNode is a ReactElement, a ReactFragment, a string, a number or an array of ReactNodes, or null, or undefined, or a boolean:
一个 ReactNode 是一个 ReactElement、一个 ReactFragment、一个字符串、一个数字或一个 ReactNode 数组,或者 null,或者 undefined,或者一个布尔值:
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
interface ReactNodeArray extends Array<ReactNode> {}
type ReactFragment = {} | ReactNodeArray;
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
JSX.Element is a ReactElement, with the generic type for props and type being any. It exists, as various libraries can implement JSX in their own way, therefore JSX is a global namespace that then gets set by the library, React sets it like this:
JSX.Element 是一个 ReactElement,props 和 type 的泛型类型是 any。它存在,因为各种库可以以自己的方式实现 JSX,因此 JSX 是一个全局命名空间,然后由库设置,React 将其设置为:
declare global {
namespace JSX {
interface Element extends React.ReactElement<any, any> { }
}
}
By example:
举例:
<p> // <- ReactElement = JSX.Element
<Custom> // <- ReactElement = JSX.Element
{true && "test"} // <- ReactNode
</Custom>
</p>
Why do the render methods of class components return ReactNode, but function components return ReactElement?
为什么类组件的render方法返回ReactNode,而函数组件返回ReactElement?
Indeed, they do return different things. Component
s return:
事实上,它们确实返回了不同的东西。Component
返回:
render(): ReactNode;
And functions are "stateless components":
函数是“无状态组件”:
interface StatelessComponent<P = {}> {
(props: P & { children?: ReactNode }, context?: any): ReactElement | null;
// ... doesn't matter
}
This is actually due to historical reasons.
这其实是有历史原因的。
How do I solve this with respect to null?
我如何解决这个关于 null 的问题?
Type it as ReactElement | null
just as react does. Or let Typescript infer the type.
键入它ReactElement | null
一样不作出反应。或者让 Typescript 推断类型。
回答by ford04
1.) What is the difference between JSX.Element, ReactNode and ReactElement?
1.) JSX.Element、ReactNode 和 ReactElement 有什么区别?
ReactElement and JSX.Elementare the result of invoking React.createElement
directly or via JSX transpilation. It is an object with type
, props
and key
. JSX.Element
is ReactElement
, whose props
and type
have type any
, so they are more or less the same.
ReactElement 和 JSX.Element是React.createElement
直接调用或通过 JSX 转译调用的结果。它是一个带有type
,props
和的对象key
。JSX.Element
is ReactElement
, whichprops
和type
have type any
,所以它们或多或少是一样的。
const jsx = <div>hello</div>
const ele = React.createElement("div", null, "hello");
ReactNodeis used as return type for render()
in class components. It also is the default type for children
attribute with PropsWithChildren
.
ReactNode用作render()
类组件的返回类型。它也是children
属性的默认类型PropsWithChildren
。
const Comp: FunctionComponent = props => <div>{props.children}</div>
// children?: React.ReactNode
It looks more complicated in the React type declarations, but is equivalentto:
它在React 类型声明中看起来更复杂,但等效于:
type ReactNode = {} | null | undefined;
// super type `{}` has absorbed *all* other types, which are sub types of `{}`
// so it is a very "broad" type (I don't want to say useless...)
You can assign almost everything to ReactNode
. I usually would prefer stronger types, but there might be some valid cases to use it.
您几乎可以将所有内容分配给ReactNode
. 我通常更喜欢更强的类型,但可能有一些有效的情况可以使用它。
2.) Why do the render methods of class components return ReactNode, but function components return ReactElement?
2.) 为什么类组件的render方法返回ReactNode,而函数组件返回ReactElement?
tl;dr:It is a current TS type incompatibility not related to core React.
tl;dr:这是与核心 React 无关的当前 TS 类型不兼容。
TS class component: returns
ReactNode
withrender()
, more permissive than React/JSTS function component: returns
JSX.Element | null
, more restrictive than React/JS
TS类组件:返回
ReactNode
与render()
比阵营/ JS更宽容TS 函数组件:返回
JSX.Element | null
,比 React/JS 限制更多
In principle, render()
in React/JS class components supports the same return typesas a function component. With regard to TS, the different types are a type inconsistency still kept due to historical reasons and the need for backwards-compatibility.
原则上,render()
React/JS 类组件支持与函数组件相同的返回类型。对于TS,不同类型是由于历史原因和向后兼容的需要仍然保持的类型不一致。
Ideally a valid return typewould probably look more like this:
理想情况下,有效的返回类型可能看起来更像这样:
type ComponentReturnType = ReactElement | Array<ComponentReturnType> | string | number
| boolean | null // Note: undefined is invalid
3.) How do I solve this with respect to null?
一些选项:3.) 我该如何解决 null 的问题?
// Use type inference; inferred return type is `JSX.Element | null`
const MyComp1 = ({ condition }: { condition: boolean }) =>
condition ? <div>Hello</div> : null
// Use explicit function return types; Add `null`, if needed
const MyComp2 = (): JSX.Element => <div>Hello</div>;
const MyComp3 = (): React.ReactElement => <div>Hello</div>;
// Option 3 is equivalent to 2 + we don't need to use a global (JSX namespace)
// Use built-in `FunctionComponent` or `FC` type
const MyComp4: React.FC<MyProps> = () => <div>Hello</div>;
Note:Avoiding React.FC
won't saveyou from the JSX.Element | null
return type restriction.
注意:避免React.FC
不会使您免于JSX.Element | null
返回类型限制。
Create React App recently dropped React.FC
from its template, as it has some quirks like an implicit {children?: ReactNode}
type definition. So using React.FC
sparingly might be preferable.
Create React App 最近从其模板中删除React.FC
,因为它有一些像隐式{children?: ReactNode}
类型定义这样的怪癖。因此,React.FC
谨慎使用可能更可取。
const MyCompFragment: FunctionComponent = () => <>"Hello"</>
const MyCompCast: FunctionComponent = () => "Hello" as any
// alternative to `as any`: `as unknown as JSX.Element | null`