我正在尝试利用 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[]
。
编辑:限制子道具的接口而不是直接限制子组件的类型也很好,因为我需要做的就是从子组件中拉出一些特定的道具。
编辑 2:事实证明这种方法可以防止警告,但根据评论 TabProps
没有正确检查。
您应该尝试像这样设置接口 TabbedViewProps 的子级
interface TabbedViewProps { children?: React.ReactElement<TabProps>[] }
这里的想法不是告诉您的 TabbedView
有一个 Tab
数组,而是告诉您的 TabbedView
他有一个 element
数组,它采用特定的道具。在您的情况下 TabProps
。
编辑(感谢 Matei):
interface TabbedViewProps {
children?: React.ReactElement<TabProps>[] | React.ReactElement<TabProps>
}
作为指针,将 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
而不是它们的 JSX 所需的道具,并将它们呈现在 TabbedView
中:
interface TabbedViewProps {
children?: never;
tabs?: TabProps[];
}
...
const TabbedView: React.FC<TabbedViewProps > = ({ tabs }) => {
return (
...
{ tabs.map(tab => <Tab key={ ... } { ...tab } />) }
...
);
};
我试图断言类型。您可以抛出或忽略。
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 渲染方法中返回的类型是 JSX.Element。这就是导致您的问题的原因。 TabbedView 期待 Tab 类型的子数组。我不确定您是否可以将某个组件指定为子类型。它可以是字符串或 JSX.Element。你能显示 Tab 的定义文件吗?
查看 https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts 以了解 JSX.Element 界面的外观。
children?: Array<React.ReactChild> | React.ReactChild
。这样,组件甚至可以接受一个孩子,而不一定是一组孩子。children
类型,TypeScript 也不会检查子项的类型。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) =>
。