TypeScript和React-子类型?

Aso*_*ool 40 jsx typescript reactjs typescript2.0

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

import * as React from 'react';

export interface AuxProps  { 
    children: React.ReactNode
 }


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

export default aux;
Run Code Online (Sandbox Code Playgroud)

还有另一个组件:

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;
Run Code Online (Sandbox Code Playgroud)

我不断收到以下错误:

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

如何正确输入?

Wil*_*ilk 66

您可以使用ReactChildrenReactChild

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

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

export default Aux;
Run Code Online (Sandbox Code Playgroud)

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

interface AuxProps {
  children: ReactChild | ReactChild[] | ReactChildren | ReactChildren[];
}
Run Code Online (Sandbox Code Playgroud)

  • 我不同意。与“ReactChild”和“ReactChildren”相比,创建一个类型/接口作为“ReactNode”更好,因为它不仅仅接受ReactChild/ReactChildren。或者更好的是,像其他人提到的那样使用“PropsWithChildren”。 (4认同)
  • 谢谢你!但是,我认为 `ReactChildren` 不是正确的类型。我认为`孩子们:ReactChild | ReactChild[]` 就足够了,或者只是 `ReactNode` (3认同)
  • 对于任何来到这里的人来说,这是错误的。`ReactChildren` 不等于 `ReactChild[]`,因为它是实用函数的类型。https://reactjs.org/docs/react-api.html#reactchildren。如果你使用`ReactChild | ReactChildren` ,您将无法将子项作为数组传递。 (2认同)

Sib*_*ren 43

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

type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;
Run Code Online (Sandbox Code Playgroud)

  • 这正是我一直在做的事情,我认为这是使用正确打字的更干净的方法。 (4认同)
  • 最干净的解决方案 (2认同)
  • 我喜欢这个解决方案,因为它是可扩展的。`type AuthProviderProps = React.PropsWithChildren&lt;{}&gt;` 允许我封装 React 类型,并在需要时使用我自己的类型进行扩展。 (2认同)
  • 最干净的方式,我一直在寻找的方式 (2认同)

Kar*_*ski 25

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

但是,当前定义为return的函数React.ReactNode,这是一个更广泛的类型。正如React类型所说的那样:

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
Run Code Online (Sandbox Code Playgroud)

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

const aux: React.FC<AuxProps> = props =>
  <>{props.children}</>;
Run Code Online (Sandbox Code Playgroud)

  • 如果 `children` 是一个数组则不然。如果是这种情况,您需要将它们包装在单个节点中或使用 React Fragments。 (4认同)
  • 它抱怨是因为“children”是一个恰好只包含 1 个项目的元素列表。我认为如果你这样做 `return React.Children.count(children) &gt; 1 就会起作用?&lt;&gt;{children}&lt;/&gt;:孩子[0]`@sanfilippopablo (2认同)

sun*_*sen 19

这对我有用:

interface Props {
  children: JSX.Element[] | JSX.Element
}
Run Code Online (Sandbox Code Playgroud)

  • 定义还不够广泛。这个孩子可能是一个字符串。 (4认同)
  • 这不适用于 JavaScript 表达式,因为子级 `&lt;MyComponent&gt;{ 条件 ? &lt;span&gt;测试&lt;/span&gt;:null}&lt;/MyComponent&gt;`。使用 `children: ReactNode` 就可以了。 (2认同)
  • 或者像其他人提到的那样使用“PropsWithChildren”。我个人更喜欢它而不是“孩子:React.ReactNode” (2认同)

小智 19

import { ReactNode, FC } from 'react'

type Props = { children: ReactNode }

const App: FC<Props> = ({children}) => (<div>{children}</div>)
Run Code Online (Sandbox Code Playgroud)

  • FC已经有孩子了,所以不需要重新声明 (2认同)

jsi*_*ina 15

你可以像这样声明你的组件:

const MyComponent: React.FunctionComponent = (props) => {
    return props.children;
}
Run Code Online (Sandbox Code Playgroud)

  • 今天的普遍共识是 React.FunctionComponent(或简写 React.FC)[不鼓励](https://github.com/facebook/create-react-app/pull/8177)。在你的情况下,我会删除 `React.FC` 用法,只做 `const MyComponent = ({children}: PropsWithChildren&lt;{}&gt;)` (7认同)

Gap*_*sym 14

AReact Node是以下类型之一:

  • Boolean (忽略)
  • nullundefined(被忽略)
  • Number
  • String
  • A React element(结果JSX
  • 上述任何一项的数组,可能是嵌套的


Rid*_*idd 13

只是 children: React.ReactNode

  • @JanacMeena,这很有趣,但是人们在不知道应该添加到儿童元素中的类型时发现了这个问题。这只是 Google 上最先出现的主题之一。因此,如果您不知道向元素添加什么 TS 类型,您可能会在 google 上搜索“typescript React Children”之类的内容,找到此主题和第一个答案,即使问题完全不同:) (14认同)
  • 这是这里的正确答案!`JSX.Element` 还不够好,因为有效的 React 子元素可能是字符串、布尔值、null...出于同样的原因,`ReactChild` 也不完整 (6认同)
  • 或 `PropsWithChildren` (4认同)
  • @PierreFerry 问题是,几乎“任何东西”都可以分配给“ReactNode”。它在类型安全方面没有帮助,类似于将“children”输入为“any” - 请参阅我的[答案](/sf/answers/4250515531/)以获取解释。 (3认同)
  • 困惑……这不是OP已经拥有的吗? (3认同)
  • 感谢您的回复@ford04。在我的用例中,我希望孩子们是松散的类型。我的组件接受任何类型的有效 React 子组件。所以我相信这仍然是我一直在寻找的答案:) (2认同)

for*_*d04 12

函数组件返回类型仅限JSXElement | null于 TypeScript。这是当前的类型限制,纯 React允许更多返回类型。

最小的演示片段

您可以使用类型断言或片段作为解决方法:

const Aux = (props: AuxProps) => <>props.children</>; 
const Aux2 = (props: AuxProps) => props.children as ReactElement; 
Run Code Online (Sandbox Code Playgroud)

ReactNode

children: React.ReactNode如果目标是为Aux.

几乎任何东西都可以分配给当前ReactNode类型,相当于{} | undefined | null. 对于您的情况,更安全的类型可能是:

interface AuxProps {
  children: ReactElement | ReactElement[]
}
Run Code Online (Sandbox Code Playgroud)

例子:

鉴于Aux需要 React 元素 as children,我们不小心在其中添加了 a string。然后上面的解决方案ReactNode- 看看链接的操场相比会出错。

Typedchildren对于非 JSX 道具也很有用,比如Render Prop回调。


Nic*_*yme 10

查找任何类型的一般方法是通过示例。打字稿的美妙之处在于您可以访问所有类型,只要您拥有正确的@types/文件。

为了自己回答这个问题,我只是想到了一个具有childrenprop的组件 react 使用。想到的第一件事是什么?怎么样<div />

您需要做的就是打开vscode.tsx在 react 项目中创建一个新文件@types/react

import React from 'react';

export default () => (
  <div children={'test'} />
);

Run Code Online (Sandbox Code Playgroud)

将鼠标悬停在children道具上会显示类型。你知道什么——它的类型是ReactNode(不需要ReactNode[])。

在此处输入图片说明

然后,如果您单击类型定义,它会直接将您带到children来自DOMAttributes接口的定义。

// node_modules/@types/react/index.d.ts
interface DOMAttributes<T> {
  children?: ReactNode;
  ...
}
Run Code Online (Sandbox Code Playgroud)

注意:这个过程应该用于查找任何未知类型!他们都在那里等着你找到他们:)


fra*_*cis 10

您还可以使用JSX.ElementChildrenAttribute

export default function Layout({children}: JSX.ElementChildrenAttribute) {
    return <div>
        {children}
    </div>
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*e S 9

来自 TypeScript 站点:https : //github.com/Microsoft/TypeScript/issues/6471

推荐的做法是将 props 类型写为 {children?: any}

那对我有用。子节点可以是许多不同的东西,因此显式类型可能会遗漏案例。

这里有关于后续问题的更长讨论:https : //github.com/Microsoft/TypeScript/issues/13618,但 any 方法仍然有效。


小智 7

对我来说“JSX.Element”有效,

interface childrenProps {
    children: JSX.Element;
}

const index = ({ children }: childrenProps) => {
    return (
        <>
            <NavBar />
            {children}
        </>
    );
};

export default index;
Run Code Online (Sandbox Code Playgroud)


Tim*_*les 6

这些答案似乎已经过时——React 现在有一个内置的 type PropsWithChildren<{}>。它的定义类似于此页面上的一些正确答案:

type PropsWithChildren<P> = P & { children?: ReactNode };


Mr.*_*har 5

这一直对我有用:

type Props = {
  children: JSX.Element;
};
Run Code Online (Sandbox Code Playgroud)


Rei*_*ard 5

我正在使用以下

type Props = { children: React.ReactNode };

const MyComponent: React.FC<Props> = ({children}) => {
  return (
    <div>
      { children }
    </div>
  );

export default MyComponent;

Run Code Online (Sandbox Code Playgroud)

  • 今天的普遍共识是 React.FunctionComponent(或简写 React.FC)[不鼓励](https://github.com/facebook/create-react-app/pull/8177)。在你的情况下,我会删除 `React.FC` 用法,只做 `const MyComponent = ({children}: PropsWithChildren&lt;{}&gt;)` (4认同)
  • 如果您使用的是“React.FC”,则无需包含“children”类型,因为它已经在基本 FC 类型上定义了。 (2认同)