Javascript 何时使用JSX.Element vs ReactNode vs ReactElement?

Javascript 何时使用JSX.Element vs ReactNode vs ReactElement?,javascript,reactjs,typescript,Javascript,Reactjs,Typescript,我目前正在将React应用程序迁移到TypeScript。到目前为止,这工作得很好,但是我的render函数的返回类型和我的函数组件都有问题 到目前为止,我一直使用JSX.Element作为返回类型,现在如果组件决定不呈现任何内容,即返回null,这将不再有效,因为null对于JSX.Element来说不是有效的值。这是我旅程的开始,因为现在我搜索了web,发现您应该使用ReactNode,它还包括null以及其他一些可能发生的事情。这似乎是更好的选择 但是,现在在创建函数组件时,TypeScr

我目前正在将React应用程序迁移到TypeScript。到目前为止,这工作得很好,但是我的
render
函数的返回类型和我的函数组件都有问题

到目前为止,我一直使用
JSX.Element
作为返回类型,现在如果组件决定不呈现任何内容,即返回
null
,这将不再有效,因为
null
对于
JSX.Element
来说不是有效的值。这是我旅程的开始,因为现在我搜索了web,发现您应该使用
ReactNode
,它还包括
null
以及其他一些可能发生的事情。这似乎是更好的选择

但是,现在在创建函数组件时,TypeScript会抱怨
ReactNode
类型。同样,经过一些搜索,我发现对于函数组件,应该使用
ReactElement
。但是,如果我这样做,兼容性问题就消失了,但是现在TypeScript再次抱怨
null
不是有效值

长话短说,我有三个问题:

  • JSX.Element
    ReactNode
    ReactElement
    之间有什么区别
  • 为什么类组件的
    render
    方法返回
    ReactNode
    ,而函数组件返回
    ReactElement
  • 对于
    null
    ,如何解决此问题
  • 元素、ReactNode和ReactElement之间的区别是什么

    ReactElement是具有类型和道具的对象

     type Key = string | number
    
     interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
        type: T;
        props: P;
        key: Key | null;
    }
    
    函数是“无状态组件”:

    接口组件{
    (props:P&{children?:ReactNode},context?:any):ReactElement | null;
    //…没关系
    }
    
    这实际上是由于

    关于null,我如何解决这个问题

    将其输入为
    ReactElement | null
    ,就像react一样。或者让Typescript推断类型

    1.)JSX.Element、ReactNode和ReactElement之间有什么区别

    ReactElement和JSX.Element 是直接调用或通过JSX Transfilation调用的结果。它是一个具有
    类型
    道具
    的对象。是
    ReactElement
    ,其
    props
    type
    具有type
    any
    ,因此它们大致相同

    const jsx = <div>hello</div>
    const ele = React.createElement("div", null, "hello");
    
    在中,它看起来更复杂,但相当于:

    您可以将几乎所有内容分配给
    ReactNode
    。我通常更喜欢更强的类型,但可能会有一些有效的情况下使用它


    2.)为什么类组件的呈现方法返回ReactNode,而函数组件返回ReactElement

    tl;dr:这是当前TS类型的不兼容

    • TS类组件:使用
      render()
      返回
      ReactNode
      ,比React/JS更具权限

    • TS函数组件:返回
      JSX.Element | null
      ,比React/JS更严格

    原则上,
    render()
    在React/JS类组件中作为函数组件。关于TS,由于历史原因和向后兼容性的需要,不同的类型仍然是一种类型不一致性

    理想情况下,a可能更像这样:

    declare global {
      namespace JSX {
        interface Element extends React.ReactElement<any, any> { }
      }
    }
    
    type ComponentReturnType = ReactElement | Array<ComponentReturnType> | string | number 
      | boolean | null // Note: undefined is invalid
    

    我很惊讶会出现这种情况,因为通常不需要使用组件指定返回类型。您要为组件做什么类型的签名?类的
    类示例扩展组件{
    ,函数组件的
    常量示例:FunctionComponent=(props)=>{
    (其中
    ExampleProps
    是预期props的接口)。然后这些类型有足够的信息来推断返回类型。这些类型是在@NicholasTower定义的。我们的linting规则强制显式地提供返回类型,这就是为什么会出现这种情况(这是一件好事,因为你对自己所做的事情思考得更多,这有助于理解,而不是让编译器推断一切).很公平,我没有想到林廷规则。@Jonaswillms谢谢你的链接,但我不认为这回答了我的问题。谢谢你的详细回答!这完美地回答了问题1,但仍然没有回答问题2和问题3。你也能提供一些关于它们的指导吗?@goloRoden当然,我现在只是有点累,没有花点时间浏览手机上的类型…;)Hi@Jonaswillms。关于“它们没有。ReactComponent定义为:render():JSX.Element | null | false;”,你在哪里看到的?它看起来像是将ReactNode返回给我()还有一个小的打字错误,我认为
    ReactComponent
    应该是
    React.Component
    Component
    @MarkDoliner奇怪,我可以发誓我从文件中复制了那种类型……不管怎样,你完全正确,我会编辑的伙计们,网上有关于React&typescript的正式文档吗?
     render(): ReactNode;
    
     interface StatelessComponent<P = {}> {
        (props: P & { children?: ReactNode }, context?: any): ReactElement | null;
        // ... doesn't matter
    }
    
    const jsx = <div>hello</div>
    const ele = React.createElement("div", null, "hello");
    
    const Comp: FunctionComponent = props => <div>{props.children}</div> 
    // children?: React.ReactNode
    
    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...)
    
    type ComponentReturnType = ReactElement | Array<ComponentReturnType> | string | number 
      | boolean | null // Note: undefined is invalid
    
    // 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>;
    
    const MyCompFragment: FunctionComponent = () => <>"Hello"</>
    const MyCompCast: FunctionComponent = () => "Hello" as any 
    // alternative to `as any`: `as unknown as JSX.Element | null`