我有一个非常简单的功能组件如下:
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]
我如何正确地输入这个?
为了在JSX中使用<Aux>,它需要是一个返回ReactElement<any> | null的函数。这就是函数分量的定义。
然而,它目前被定义为一个返回React的函数。ReactNode,这是一个更广泛的类型。正如React类型所说:
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
通过将返回值包装到React Fragment(<></>)中,确保不需要的类型被中和:
const aux: React.FC<AuxProps> = props =>
<>{props.children}</>;
查找任何类型的一般方法是通过示例。typescript的美妙之处在于,只要你有正确的@types/ files,你就可以访问所有类型。
为了自己回答这个问题,我想到了一个react使用的组件,它有子道具。你首先想到的是什么?<div />怎么样?
你所需要做的就是打开vscode,用@types/react在react项目中创建一个新的。tsx文件。
import React from 'react';
export default () => (
<div children={'test'} />
);
将鼠标悬停在儿童道具上显示类型。你知道什么——它的类型是ReactNode(不需要ReactNode[])。
然后,如果单击进入类型定义,它会直接将您带到来自DOMAttributes接口的子定义。
// 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;
ReactNode
孩子们:反应。如果目标是为Aux提供强类型,那么ReactNode可能不是最优的。
几乎任何东西都可以赋值给当前的ReactNode类型,这相当于{}| undefined | null。对于你的情况,更安全的类型可能是:
interface AuxProps {
children: ReactElement | ReactElement[]
}
例子:
由于Aux需要React元素作为子元素,我们意外地向它添加了一个字符串。然后上面的解决方案将错误与ReactNode对比-看看链接操场。
类字子函数对于非jsx道具也很有用,比如Render Prop回调函数。
你可以使用ReactChildren和ReactChild:
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组件都应该返回null或react。元素,但道具的类型。children是React。ReactNode,所以你需要使用这些道具。子元素,使babel配置元素的构造函数。
任何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>
)
你也可以扩展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}) => {