我有一个非常简单的功能组件如下:
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]
如何正确输入?
const layout React.FC = (props) => {/*component body*/}
({ title, children }: React.PropsWithChildren<XyzComponentPropsType>
=> {}`
只需 children: React.ReactNode
。
为了在 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}</>;
children
包装在 React 片段中。介意解释吗?在 React 中,仅 return children;
是完全有效的。
children
是一个数组,则不是。如果是这种情况,您需要将它们包装在单个节点中或使用 React Fragments。
return React.Children.count(children) > 1 ? <>{children}</> : children
,但打字稿抱怨这一点。我只用 <>{children}</>
替换了它。
children
是恰好包含 1 个项目的元素列表。我认为如果您这样做 return React.Children.count(children) > 1 ? <>{children}</> : children[0]
@sanfilippopablo 会起作用
<React.Fragment>
围绕 {props.children}
我也没有返回任何东西。
您可以使用 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[];
}
ReactChildren
不等于 ReactChild[]
,因为它是效用函数的类型。 reactjs.org/docs/react-api.html#reactchildren。如果您使用 ReactChild | ReactChildren
,您将无法将孩子作为数组传递。
ReactChildren
是正确的类型。我认为 children: ReactChild | ReactChild[]
就足够了,或者只是 ReactNode
ReactChild
和 ReactChildren
相比,将类型/接口创建为 ReactNode
更好,因为它不仅接受 ReactChild/ReactChildren。或者更好的是,使用其他人提到的 PropsWithChildren
。
这对我有用:
interface Props {
children: JSX.Element[] | JSX.Element
}
编辑我建议现在改用 children: React.ReactNode
。
<MyComponent>{ condition ? <span>test</span> : null}</MyComponent>
的 JavaScript 表达式。使用 children: ReactNode
即可。
PropsWithChildren
。我个人更喜欢它而不是 children: React.ReactNode
您也可以使用 React.PropsWithChildren<P>
。
type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;
type AuthProviderProps = React.PropsWithChildren<{}>
允许我封装 React 类型,并在需要时使用我自己的类型进行扩展。
ReactChild | ReactChildren
的解决方案。
React Node
是以下类型之一:
布尔值(被忽略)
null 或 undefined(被忽略)
数字
细绳
一个 React 元素(JSX 的结果)
上述任何一个的数组,可能是嵌套的
你可以像这样声明你的组件:
const MyComponent: React.FunctionComponent = (props) => {
return props.children;
}
React.FC
的使用,只做 const MyComponent = ({children}: PropsWithChildren<{}>)
函数组件返回类型在 TypeScript 中被限制为 JSXElement | null
。这是当前的类型限制,纯 React allows more 返回类型。
您可以使用类型断言或 Fragments 作为解决方法:
const Aux = (props: AuxProps) => <>props.children</>;
const Aux2 = (props: AuxProps) => props.children as ReactElement;
反应节点
如果目标是为 Aux
提供强类型,则 children: React.ReactNode
可能不是最理想的。
几乎任何东西都可以分配给当前的 ReactNode
类型,相当于 {} | undefined | null
。对于您的情况,更安全的类型可能是:
interface AuxProps {
children: ReactElement | ReactElement[]
}
例子:
鉴于 Aux
需要 React 元素作为 children
,我们不小心添加了一个 string
。与 ReactNode
相比,above solution 会出错 - 看看链接的 Playground。
输入的 children
对于非 JSX 属性也很有用,例如 Render Prop 回调。
我正在使用以下
type Props = { children: React.ReactNode };
const MyComponent: React.FC<Props> = ({children}) => {
return (
<div>
{ children }
</div>
);
export default MyComponent;
React.FC
的使用,只做 const MyComponent = ({children}: PropsWithChildren<{}>)
React.FC
,则无需包含 children
类型,因为它已在基本 FC 类型中定义。
import { ReactNode, FC } from 'react'
type Props = { children: ReactNode }
const App: FC<Props> = ({children}) => (<div>{children}</div>)
查找任何类型的通用 方法是通过示例。 typescript 的优点在于您可以访问所有类型,只要您拥有正确的 @types/
文件。
为了自己回答这个问题,我只是想到了一个具有 children
属性的组件 react 使用。首先想到的是? <div />
怎么样?
您需要做的就是打开 vscode 并使用 @types/react
在 react 项目中创建一个新的 .tsx
文件。
import React from 'react';
export default () => (
<div children={'test'} />
);
将鼠标悬停在 children
道具上会显示类型。你知道什么——它的类型是ReactNode
(不需要ReactNode[]
)。
https://i.stack.imgur.com/ffpa8.png
然后,如果您单击类型定义,它会将您直接带到来自 DOMAttributes
界面的 children
的定义。
// node_modules/@types/react/index.d.ts
interface DOMAttributes<T> {
children?: ReactNode;
...
}
注意:此过程应用于查找任何未知类型!他们都在那里等着你找到他们:)
来自 TypeScript 网站:https://github.com/Microsoft/TypeScript/issues/6471
推荐的做法是将 props 类型写为 {children?: any}
这对我有用。子节点可以是许多不同的东西,因此显式键入可能会遗漏案例。
此处对后续问题进行了更长的讨论:https://github.com/Microsoft/TypeScript/issues/13618,但 any 方法仍然有效。
您也可以使用 JSX.ElementChildrenAttribute
export default function Layout({children}: JSX.ElementChildrenAttribute) {
return <div>
{children}
</div>
}
这些答案似乎已经过时 - React 现在有一个内置类型 PropsWithChildren<{}>
。它的定义类似于此页面上的一些正确答案:
type PropsWithChildren<P> = P & { children?: ReactNode };
P
是什么?
P
是组件道具的类型
interface LayoutProps {} const Layout = ({children}: PropsWithChildren<LayoutProps>) => {...}
这一直对我有用:
type Props = {
children: JSX.Element;
};
React.PropsWithChildren<{}>
或至少使用 React.ReactNode
而不是 JSX.Element
,因为它不仅仅支持 Element
类型
作为包含孩子的类型,我正在使用:
type ChildrenContainer = Pick<JSX.IntrinsicElements["div"], "children">
这种子容器类型足够通用,可以支持所有不同的情况,并且与 ReactJS API 保持一致。
因此,对于您的示例,它将类似于:
const layout = ({ children }: ChildrenContainer) => (
<Aux>
<div>Toolbar, SideDrawer, Backdrop</div>
<main>
{children}
</main>
<Aux/>
)
对我来说@Sibren 的回答不够清楚,但我找到了 this SO anwer 并将其全部内联(这可能不是最短的方法,但我发现最容易掌握的方法)。
function MyComponentWithChildren({
customProp,
children, /*notice the children are implicit*/
}: React.PropsWithChildren<{ customProp: any }>) {
return <div>{children}</div>;
}
你应该知道任何react组件都应该返回null或者React.Element,但是props.children的类型是React.ReactNode,所以需要使用Element内部的props.children来让babel配置Element的构造函数。任何 react 组件的第二条规则是命名的第一个字母应该是大写字母,以让 react 识别该组件不是 html 标签。
所以代码应该是这样的。
const Aux = (props: AuxProps) => <>props.children</>;
另一个提示,如果您仍在使用打字稿,功能组件应该是 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>
)
这个解决方案对我来说非常好
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> {}
您可以创建一个简单的组件,它只输出没有 type
的 children
道具或带有 FC
的 interface
(功能组件)。您必须用空的 jsx 标记 <>
包装,因为子级可以是 undefined
或 null
:
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}) => {
React 组件应该有一个包装节点或返回一个节点数组。
您的 <Aux>...</Aux>
组件有两个节点 div
和 main
。
尝试将您的孩子包装在 div
in Aux
组件中。
import * as React from 'react';
export interface AuxProps {
children: React.ReactNode
}
const aux = (props: AuxProps) => (<div>{props.children}</div>);
export default aux;
JSX.Element
不够好,因为有效的 React 子代可能是字符串、布尔值、null...ReactChild
出于同样的原因也不完整ReactNode
。它在类型安全方面没有帮助,类似于将children
输入为any
- 请参阅我的 answer 以获得解释。PropsWithChildren