如何在 TypeScript 中使用具有 React 无状态函数组件的子组件

使用 TypeScript 和 React,我们不再需要扩展 React.Props来让编译器知道所有的 React 组件道具都可以有子道具:

interface MyProps { }


class MyComponent extends React.Component<MyProps, {}> {
public render(): JSX.Element {
return <div>{this.props.children}</div>;
}
}

然而,无状态函数组件似乎并非如此:

const MyStatelessComponent = (props: MyProps) => {
return (
<div>{props.children}</div>
);
};

发出编译错误:

错误: (102,17) TS2339: 类型上不存在“子类型”属性 “ MyProps”。

我猜这是因为编译器实际上无法知道在 props 参数中给出的是普通函数 children

所以问题是我们应该如何在 TypeScript 的无状态函数组件中使用子组件?

我可以回到 MyProps extends React.Props的老方法,但是 Props接口是 被标记为已废弃的,而且无状态组件没有或者支持我所理解的 Props.ref

所以我可以手动定义 children道具:

interface MyProps {
children?: React.ReactNode;
}

第一: ReactNode是正确的类型吗?

第二: 我必须把子元素写成可选的(?) ,否则消费者会认为 children应该是组件的 属性(<MyStatelessComponent children={} />) ,如果没有提供值,就会产生错误。

我好像漏掉了什么。有没有人可以澄清一下我的最后一个示例是否是在 React 中对孩子们使用无状态函数组件的方法?

129057 次浏览

反应16.8更新: 自从反应16.8以来,React.SFCReact.StatelessComponent这两个名字就不被推荐了。实际上,它们已经成为 React.FunctionComponent型或简称 React.FC的别名。

不过,你也会用同样的方式使用它们:

const MyStatelessComponent : React.FunctionComponent<MyProps> = props =>
<div>
<p>{props.propInMyProps}</p>
<p>{props.children}</p>
</div>

反应前16.8(年龄较大) :

现在,您可以使用 React.StatelessComponent<>类型,如:

const MyStatelessComponent : React.StatelessComponent<{}> = props =>
<div>{props.children}</div>

我在这里添加的是将组件的返回类型设置为 React.StatelessComponent类型。

对于具有自定义道具(如 MyProps接口)的组件:

const MyStatelessComponent : React.StatelessComponent<MyProps> = props =>
<div>
<p>{props.propInMyProps}</p>
<p>{props.children}</p>
</div>

现在,props已经获得了 children属性以及 MyProps接口的属性。

我在2.0.7版本中检查了这个

此外,为了简洁起见,可以使用 React.SFC而不是 React.StatelessComponent

你可以使用 React.PropsWithChildren<P>类型为您的道具:

interface MyProps { }


function MyComponent(props: React.PropsWithChildren<MyProps>) {
return <div>{props.children}</div>;
}

你可以用

interface YourProps { }
const yourComponent: React.SFC<YourProps> = props => {}

更简单的答案: 使用 ReactNode:

interface MyProps {
children?: React.ReactNode
}

如果 children是可选的或不是(例如有没有 ?)取决于您的组件。?是最简洁的表达方式,所以没有什么错。

关于历史: 在最初被问及时,这并不一定是正确的答案: 类型 ReactNode(几乎)是在2017年3月才以现在的形式加入 这个拉动请求的,但是今天几乎所有阅读这篇文章的人都是在一个足够现代的 React 版本上。

最后,关于将 children作为“属性”传递(在 React 行话中,将它作为“支持”而不是属性传递) : 这是可能的,但在大多数情况下,当传递 JSX 子元素时读取效果更好:

<MyComponent>
<p>This is part of the children.</p>
</MyComponent>

读起来比

<MyComponent children={<p>This is part of the children.</p>} />

您可以只向组件添加子组件,如果它连接到一个容器,那么这就是您所需要的全部。

const MyComponent = ({
children
}) => {
return <div>{children}</div>


}