提问者:小点点

如何使用TypeScript 2.3中新增的支持限制TypeScript中React子项的类型?


我试图利用最近增加的对TypeScript编译器和@类型/反应中键入儿童的支持,但很挣扎。我使用的是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[],尽管这是我使用的唯一类型的子类型。

编辑:也可以限制子道具的接口,而不是直接限制子组件的类型,因为我所需要做的就是从子组件中提取一些特定的道具。


共3个答案

匿名用户

编辑2:结果表明这种方法阻止了警告,但是根据注释TabProps没有正确检查。

您应该尝试这样设置界面选项卡ViewProps的子级

interface TabbedViewProps { children?: React.ReactElement<TabProps>[] }

这里的想法不是告诉你的TabbedView有一个Tab数组,而是告诉你的TabbedView有一个需要特定道具的元素数组。在您的情况下TabProps

编辑(thx到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>
);

你可以做的是声明一个道具,比方说选项卡: TabProps[],来传递你需要的道具来创建那些选项卡,而不是他们的JSX,并在选项卡视图中呈现它们:

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;
})}