如何使用 TypeScript 2.3 中新增的支持来限制 TypeScript 中 React Children 的类型?
Posted
技术标签:
【中文标题】如何使用 TypeScript 2.3 中新增的支持来限制 TypeScript 中 React Children 的类型?【英文标题】:How do I restrict the type of React Children in TypeScript, using the newly added support in TypeScript 2.3? 【发布时间】:2017-11-12 12:08:04 【问题描述】:我正在尝试利用 TypeScript 编译器和 @types/react 中的 recently added support for typing of children,但遇到了困难。我使用的是 TypeScript 2.3.4 版。
假设我有这样的代码:
interface TabbedViewProps children?: Tab[]
export class TabbedView extends React.Component<TabbedViewProps, undefined>
render(): JSX.Element
return <div>TabbedView</div>;
interface TabProps name: string
export class Tab extends React.Component<TabProps, undefined>
render(): JSX.Element
return <div>Tab</div>
当我尝试像这样使用这些组件时:
return <TabbedView>
<Tab name="Creatures">
<div>Creatures!</div>
</Tab>
<Tab name="Combat">
<div>Combat!</div>
</Tab>
</TabbedView>;
我收到如下错误:
ERROR in ./src/typescript/PlayerView.tsx
(27,12): error TS2322: Type ' children: Element[]; ' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<TabbedView> & Readonly< children?: ReactNode; > ...'.
Type ' children: Element[]; ' is not assignable to type 'Readonly<TabbedViewProps>'.
Types of property 'children' are incompatible.
Type 'Element[]' is not assignable to type 'Tab[] | undefined'.
Type 'Element[]' is not assignable to type 'Tab[]'.
Type 'Element' is not assignable to type 'Tab'.
Property 'render' is missing in type 'Element'.
它似乎将孩子的类型推断为Element[]
而不是Tab[]
,尽管这是我使用的唯一类型的孩子。
编辑:限制 children props 的接口也可以,而不是直接限制子组件的类型,因为我需要做的就是从子组件。
【问题讨论】:
看看 React.PropsWithChildren编辑 2:结果证明这种方法可以防止警告,但根据 cmets TabProps
没有正确检查。
您应该尝试像这样设置接口 TabbedViewProps 的子级
interface TabbedViewProps children?: React.ReactElement<TabProps>[]
这里的想法不是告诉你的TabbedView
有一个Tab
的数组,而是告诉你的TabbedView
他有一个element
的数组,它带有特定的道具。在你的情况下TabProps
。
编辑(感谢 Matei):
interface TabbedViewProps
children?: React.ReactElement<TabProps>[] | React.ReactElement<TabProps>
【讨论】:
我采用了类似的方法:children?: Array<React.ReactChild> | React.ReactChild
。这样,组件甚至可以接受一个孩子,而不一定是一个孩子数组。
我也有类似的问题。在我的例子中,我像你一样定义了子元素的类型(即 TabProps),但是当我将一个元素放置为 TabbedView 的子元素时,它的形状不像 TabProps,打字稿不会报告任何错误或警告。能给点建议或线索吗?
与@Noah 相同的问题。似乎您只能在一定程度上限制子元素,但限制子元素具有某些道具 是行不通的。它会确保它是一个元素,但道具并不重要。无赖!
我也面临同样的问题。即使我像上面那样定义了children
类型,TypeScript 也不会检查子项的类型。
看起来像用 ReactElement 包裹 props 会放松类型,以便实际允许任何元素。这是我将鼠标悬停在我的客户元素上时得到的结果:type ChartElement<T> = ReactElement<ChartProps<T>, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)>
注意|(props: any) =>
。【参考方案2】:
作为指针,将TabbedView.children
声明为:
children: React.ReactElement<TabProps> | React.ReactElement<TabProps>[];
会消除错误,但不会正确地对子项进行类型检查。也就是说,您仍然可以将 TabProps
以外的子代传递给 TabbedView
而不会出现任何错误,因此这也是有效的:
return (
<TabbedView>
<Tab name="Creatures">
<div>Creatures!</div>
</Tab>
<Tab name="Combat">
<div>Combat!</div>
</Tab>
<NotTabButValidToo />
</TabbedView>
);
你可以做的是声明一个道具,比如说tabs: TabProps[]
,传递你需要的道具来创建那些Tab
s,而不是它们的JSX,并在TabbedView
中渲染它们:
interface TabbedViewProps
children?: never;
tabs?: TabProps[];
...
const TabbedView: React.FC<TabbedViewProps > = ( tabs ) =>
return (
...
tabs.map(tab => <Tab key= ... ...tab />)
...
);
;
【讨论】:
研究了一段时间,我认为考虑到孩子的局限性,这是最好的方法 选择更糟糕的 API 只是因为类型检查器的限制对我来说似乎不是一个明智的决定。【参考方案3】:我试图断言类型。 你可以抛出或忽略。
interface TabbedViewProps
children?: React.ReactElement<ITabProps> | React.ReactElement<ITabProps>[]
并且在组件本身映射子元素并断言或忽略
React.Children.map(props.children, (tab) =>
if(tab?.type != Tab) return;
console.log(tab?.type == Tab);
return tab;
)
【讨论】:
ab?.type != Tab
中的“Tab”是什么【参考方案4】:
您在 Tab 渲染方法中返回的类型是 JSX.Element。这就是导致您的问题的原因。 TabbedView 期待 Tab 类型的子数组。我不确定您是否可以将某个组件指定为子类型。它可以是字符串或 JSX.Element。可以显示 Tab 的定义文件吗?
查看https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts 了解 JSX.Element 接口的外观。
【讨论】:
我在第一个代码块中展示了 TabbedView 和 Tab 的完整定义。对子类型 似乎 的新支持的全部意义在于允许限制组件(如果您在 PR 顶部看到它应该解决的问题),所以我认为我必须错过了什么。 您已经显示了组件的定义。不是界面。 我不太确定您要的是什么,很抱歉:(这是我的 tsx 项目中与 Tab 相关的全部代码。我很乐意尝试提供你要什么,但我想我需要一点帮助。 已编辑:仍然无法正常工作。我尝试了 React.ReactElement以上是关于如何使用 TypeScript 2.3 中新增的支持来限制 TypeScript 中 React Children 的类型?的主要内容,如果未能解决你的问题,请参考以下文章