'儿童'道具吗?

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

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;

我一直得到以下错误:

< p > (ts) JSX元素类型“ReactNode”不是JSX元素的构造函数。 类型'undefined'不能赋值给类型'ElementClass'。[2605] < / p >

我如何正确地输入这个?

478059 次浏览

为了在JSX中使用<Aux>,它需要是一个返回ReactElement<any> | null的函数。这就是EYZ2的定义。

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

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

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

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

这对我来说很管用:

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

我建议现在改用children: React.ReactNode

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

推荐的做法是将props类型写成{children?: 任何}< / p >

这对我很管用。子节点可以是很多不同的东西,因此显式类型可能会遗漏一些情况。

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

# EYZ0。

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

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

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

为了自己回答这个问题,我只是想到了一个react使用的组件,它有children道具。你首先想到的是什么?<div />怎么样?

你所需要做的就是打开vscode并在react项目中使用@types/react创建一个新的.tsx文件。

import React from 'react';


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


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

enter image description here

然后,如果你点击进入类型定义,它会直接带你到DOMAttributes接口的children的定义。

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

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

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

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

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

所以,在你的例子中,它会是这样的:

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

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

最小演示片段

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

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

# EYZ0

如果目标是为Aux提供强类型,children: React.ReactNode可能是次优的。

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

interface AuxProps {
children: ReactElement | ReactElement[]
}

例子:

鉴于Aux需要React元素作为children,我们意外地添加了string。然后以上解决方案ReactNode相比会出错-看看链接的游乐场。

键入children对于非jsx道具也很有用,比如渲染道具回调。

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

# EYZ0

你可以使用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[];
}

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

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

这对我来说一直都很有效:

type Props = {
children: JSX.Element;
};

React Node是以下类型之一:

  • Boolean(被忽略)
  • nullundefined(被忽略)
  • # EYZ0
  • # EYZ0
  • A React element (JSX的结果)
  • 上述任意一个的数组,可能是嵌套的数组

我用的是下面的

type Props = { children: React.ReactNode };


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


export default MyComponent;

您也可以使用JSX.ElementChildrenAttribute

export default function Layout({children}: JSX.ElementChildrenAttribute) {
return <div>
{children}
</div>
}
  1. 你应该知道任何应该的react组件都会返回nullReact.Element,但是props.children的类型是React.ReactNode,所以你需要在Element中使用props.children来让babel配置Element的构造函数。

  2. 任何react组件的第二条规则是命名应该的第一个字母必须是大写字母,以便react识别出该组件不是html标签。

代码应该是这样的。

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

另一个提示,如果你仍然使用typescript,函数组件的类型应该是React.FC,就像这样

type Props = {
title: string;
}


const Aux:React.FC<Props> = (props) =>
(
<div>
<h3>{props.title}</h3>
{ props.children }
{/* children is exist by default in type React.FC */}
</div>
)
import { ReactNode, FC } from 'react'


type Props = { children: ReactNode }


const App: FC<Props> = ({children}) => (<div>{children}</div>)

对我来说@Sibren的答案还不够清楚,但我找到了这个SO答案,并使它全部内联(这可能不是最短的方法,但我发现最容易掌握)。

function MyComponentWithChildren({
customProp,
children, /*notice the children are implicit*/
}: React.PropsWithChildren<{ customProp: any }>) {
return <div>{children}</div>;
}

这个解决方案对我来说非常有效

interface Props {
children: Array<ReactElement<ChildProps, JSXElementConstructor<ChildType>>>;
}

更新:一个全面的例子,这样更容易理解。

interface ChildProps {}


class ChildComponent extends React.Component<ChildProps> {}


interface ParentProps {
children: Array<ReactElement<ChildProps, JSXElementConstructor<ChildComponent>>>;
}


class ParentComponent extends React.Component<ParentProps> {}

您可以创建一个简单的组件,只输出children道具而不输出type,或者输出interface而输出FC(功能组件)。你必须用空的jsx标签<>来包装,因为子标签可以是undefinednull:

import { FC } from "react";


export const Layout: FC = (props) => {
return <>{props.children}</>;
};

——或——

import { FC } from "react";


export const Layout: FC = ({ children }) => <>{children}</>;

你也可以扩展React。PropsWithChildren到你的界面,其中包含children属性。

interface Props extends React.PropsWithChildren{
listItems: Items[],
clickItem?: () => void,
    

}

或者您可以直接定义子元素

interface Props{
listItems: Items[],
clickItem?: () => void,
children: React.ReactNode
}


const List:FC<Props> = ({listItems,clickItem,children}) =>  {


return (
<>
{children}
</>
    

)
}

或者你可以这样做。这是定义道具类型的另一种方式

const List = ({ children }: {children: React.ReactNode}) =>  {

For me "JSX.Element"的作品,

interface childrenProps {
children: JSX.Element;
}


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


export default index;