TypeScript和React-子类型?


137

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

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元素的构造函数。类型“未定义”不能分配给类型“ ElementClass”。[2605]

如何正确输入?

Answers:


132

只是 children: React.ReactNode


这是正确的答案!JSX.Element不够好,因为有效的React子代可能是字符串,布尔值,null…… ReactChild出于同样的原因,它也不完整
Pierre Ferry

2
@PierreFerry问题是,几乎所有内容都可以分配给ReactNode。它在类型安全方面无济于事,类似于键入childrenany-请参阅我的答案以获取解释。
ford04

感谢您的回复@ ford04。在我的用例中,我希望孩子们能打字。我的组件接受任何有效的React子代。所以我相信这仍然是我一直在寻找的答案:)
皮埃尔·费里

47

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

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

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

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

const aux: React.FC<AuxProps> = props =>
  <>{props.children}</>;

我不明白为什么需要将它包装children在React Fragment中。介意解释吗?在React中,just完全有效return children;
sanfilippopablo

1
如果children是数组则不是。如果是这种情况,您需要将它们包装在单个节点中或使用React Fragments。
卡罗尔·马耶夫斯基(Camol Majewski)

是的,在我的代码中,我有:return React.Children.count(children) > 1 ? <>{children}</> : children,但是打字稿对此有所抱怨。我用替换了它<>{children}</>
sanfilippopablo

2
它抱怨是因为children一个元素列表恰好只包含一项。我认为,如果您进行了return React.Children.count(children) > 1 ? <>{children}</> : children[0]@sanfilippopablo
tamj0rd2 '19

在新版本的React中似乎不起作用。我已登录控制台,可以确认我有一个儿童道具,但是即使<React.Fragment>周围,{props.children}我也不会退回任何东西。
标记

34

这对我有用:

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

编辑,我建议children: React.ReactNode现在改为使用。


8
定义还不够广泛。这个孩子可能是一个字符串。
Mike S

至少该示例对我有用,因为我的组件应该期望1个或更多JSX.Elements。谢谢!
Italo Borges

1
作为子代,这不适用于JavaScript表达式<MyComponent>{ condition ? <span>test</span> : null}</MyComponent>。使用children: ReactNode将起作用。
Nickofthyme,

10

您可以这样声明您的组件:

const MyComponent: React.FunctionComponent = (props) => {
    return props.children;
}

9

您可以使用ReactChildrenReactChild

import React, { ReactChildren, ReactChild } from 'react';

interface AuxProps {
  children: ReactChild | ReactChildren;
}

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

export default Aux;


6

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

最小的演示片段

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

const Aux = (props: AuxProps) => <>props.children</>; 
const Aux2 = (props: AuxProps) => props.children as ReactElement; 

ReactNode

children: React.ReactNode如果目标是为设置强类型,则可能不是最佳选择Aux

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

interface AuxProps {
  children: ReactElement | ReactElement[]
}

例:

鉴于Aux需要将React元素设置为children,我们不小心在其中添加了一个string。与上述相反,上述解决方案会出错ReactNode-看一下链接的游乐场。

Typed children对于非JSX道具(例如Render Prop回调)也很有用。


5

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

type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;

3

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

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

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

import React from 'react';

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

将鼠标悬停在children道具上会显示类型。而且您知道吗-它的类型是ReactNode(不需要ReactNode[])。

在此处输入图片说明

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

// node_modules/@types/react/index.d.ts
interface DOMAttributes<T> {
  children?: ReactNode;
  ...
}

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


2

作为包含孩子的类型,我正在使用:

type ChildrenContainer = Pick<JSX.IntrinsicElements["div"], "children">

这种子容器类型足够通用,可以支持所有不同的情况,并且与ReactJS API保持一致。

因此,以您的示例为例:

const layout = ({ children }: ChildrenContainer) => (
    <Aux>
        <div>Toolbar, SideDrawer, Backdrop</div>
        <main>
            {children}
        </main>
    <Aux/>
)


-2

React组件应具有单个包装器节点或返回节点数组。

您的<Aux>...</Aux>组件有两个节点divmain

尝试将孩子包装在divin Aux组件中。

import * as React from 'react';

export interface AuxProps  { 
  children: React.ReactNode
}

const aux = (props: AuxProps) => (<div>{props.children}</div>);

export default aux;

1
不对。在React 16+中已不再是这种情况,如果出现这种情况,错误也会说出来
Andrew Li
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.