TypeScript 和 React - 儿童打字?

IT技术 reactjs typescript jsx typescript2.0
2021-03-25 22:38:32

我有一个非常简单的功能组件如下:

import * as React from 'react';

export interface AuxProps  { 
    children: React.ReactNode
 }


const aux = (props: AuxProps) => props.children;

export default aux;

另一个组件:

import * as React from "react";

export interface LayoutProps  { 
   children: React.ReactNode
}

const layout = (props: LayoutProps) => (
    <Aux>
        <div>Toolbar, SideDrawer, Backdrop</div>
        <main>
            {props.children}
        </main>
    <Aux/>
);

export default layout;

我不断收到以下错误:

[ts] JSX 元素类型“ReactNode”不是 JSX 元素的构造函数。类型 'undefined' 不能分配给类型 'ElementClass'。[2605]

我如何正确输入?

6个回答

只是children: React.ReactNode

困惑......这不是OP已经拥有的吗?
2021-05-23 22:38:32
感谢您的回复@ford04。在我的用例中,我希望孩子们是松散的类型。我的组件接受任何类型的有效 React 子项。所以我相信这仍然是我一直在寻找的答案:)
2021-05-24 22:38:32
或者 PropsWithChildren
2021-05-24 22:38:32
这是这里的正确答案!JSX.Element不够好,因为有效的 React 子项可能是字符串、布尔值、空值......ReactChild出于同样的原因也不完整
2021-05-31 22:38:32
@PierreFerry 问题是,几乎任何东西都可以分配给ReactNode. 它不利于在类型安全,类似打字方面childrenany-看到我的回答作出解释。
2021-06-20 22:38:32

为了<Aux>在您的 JSX 中使用,它需要是一个返回ReactElement<any> | null. 这就是功能组件的定义

但是,它目前被定义为一个返回 的函数React.ReactNode,这是一个更广泛的类型。正如 React 类型所说:

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

通过将返回值包装到 React Fragment ( <></>)中,确保消除不需要的类型

const aux: React.FC<AuxProps> = props =>
  <>{props.children}</>;
它抱怨是因为children是一个元素列表,它恰好只包含 1 个项目。我认为如果你做了return React.Children.count(children) > 1 ? <>{children}</> : children[0]@sanfilippopablo,它会起作用
2021-05-30 22:38:32
这似乎不适用于较新版本的 React。我控制台登录并可以确认我有一个儿童道具,但即使在<React.Fragment>周围{props.children}我也没有返回任何东西。
2021-06-02 22:38:32
是的,在我的代码中,我有:return React.Children.count(children) > 1 ? <>{children}</> : children,但是typescript对此有所抱怨。我用 just 替换了它<>{children}</>
2021-06-03 22:38:32
不是如果children是一个数组。如果是这种情况,您需要将它们包装在单个节点中或使用 React Fragments。
2021-06-06 22:38:32
我不明白为什么需要包装children在 React Fragment 中。介意解释一下吗?在 React 中,它对return children;.
2021-06-20 22:38:32

您可以使用ReactChildrenReactChild

import React, { ReactChildren, ReactChild } from 'react';
 
interface AuxProps {
  children: ReactChild | ReactChildren;
}

const Aux = ({ children }: AuxProps) => (<div>{children}</div>);

export default Aux;

如果您需要传递元素的平面数组:

interface AuxProps {
  children: ReactChild | ReactChild[] | ReactChildren | ReactChildren[];
}
谢谢!但是,我认为ReactChildren这里不是正确的类型。我认为children: ReactChild | ReactChild[]足够或只是ReactNode
2021-05-30 22:38:32
我不同意。ReactNodeReactChild/ReactChildren相比,创建类型/接口更好ReactChildReactChildren因为它接受的不仅仅是 ReactChild/ReactChildren。或者甚至更好,PropsWithChildren像其他人提到的那样使用
2021-06-08 22:38:32
@kay 谢谢。我在答案中添加了平面数组定义。它也应该涵盖您的情况。让我知道。
2021-06-11 22:38:32
对于最终来到这里的任何人来说,这是错误的。 ReactChildren不等于,ReactChild[]因为它是效用函数的类型。reactjs.org/docs/react-api.html#reactchildren如果您使用ReactChild | ReactChildren,您将无法将子项作为数组传递。
2021-06-21 22:38:32

这对我有用:

interface Props {
  children: JSX.Element[] | JSX.Element
}

编辑我建议children: React.ReactNode现在使用

至少这个例子对我有用,因为我的组件应该期待 1 个或多个 JSX.Elements。谢谢!
2021-05-26 22:38:32
这不适用于作为 children 的 JavaScript 表达式<MyComponent>{ condition ? <span>test</span> : null}</MyComponent>使用children: ReactNode将工作。
2021-05-29 22:38:32
PropsWithChildren像其他人提到的那样使用我个人更喜欢它children: React.ReactNode
2021-06-02 22:38:32
这个定义不够宽泛。孩子可能是一个字符串。
2021-06-08 22:38:32

您也可以使用React.PropsWithChildren<P>.

type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;
我喜欢这个解决方案,因为它是可扩展的。type AuthProviderProps = React.PropsWithChildren<{}>允许我封装 React 类型,并在需要时扩展我自己的类型。
2021-06-01 22:38:32
这正是我一直在做的事情,我认为这是使用正确打字的更简洁的方式。
2021-06-06 22:38:32