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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44475309/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:37:39  来源:igfitidea点击:

How do I restrict the type of React Children in TypeScript, using the newly added support in TypeScript 2.3?

reactjstypescript

提问by Christopher Armstrong

I'm trying to take advantage of the recently added support for typing of childrenin the TypeScript compiler and @types/react, but struggling. I'm using TypeScript version 2.3.4.

我正在尝试利用最近添加的对 TypeScript 编译器和 @types/react中儿童输入的支持,但很挣扎。我正在使用 TypeScript 2.3.4 版。

Say I have code like this:

假设我有这样的代码:

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

When I try to use these components like so:

当我尝试像这样使用这些组件时:

return <TabbedView>
  <Tab name="Creatures">
    <div>Creatures!</div>
  </Tab>
  <Tab name="Combat">
    <div>Combat!</div>
  </Tab>
</TabbedView>;

I get an error as follows:

我收到如下错误:

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'.

It seems to be inferring the type of children as just Element[]instead of Tab[]even though that's the only type of children I'm using.

它似乎在推断孩子的类型,Element[]而不是Tab[]即使这是我使用的唯一类型的孩子。

EDIT: It would also be fine to restrict the interface of the children propsinstead of restricting the type of the children components directly, since all I need to do is pull some specific props out of the children components.

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

回答by Pierre Ferry

Edit 2: Turns out that this approach prevent the warning, but according to the comments TabPropsaren't properly checked.

编辑 2:原来这种方法可以防止警告,但根据评论TabProps没有正确检查。

You should try to set children of interface TabbedViewProps like so

您应该尝试像这样设置界面 TabbedViewProps 的子项

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

The idea here is not to tell your TabbedViewhas an array of Tab, but instead tell your TabbedViewhe has an array of elementwhich takes specific props. In your case TabProps.

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

Edit ( thx to Matei ):

编辑(感谢 Matei):

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

回答by Danziger

As pointer out already, declaring TabbedView.childrenas:

已经作为指针,声明TabbedView.children为:

children: React.ReactElement<TabProps> | React.ReactElement<TabProps>[];

Will get rid of the error, but it won't be type-checking the children properly. That is, you will still be able to pass children other than TabPropsto TabbedViewwithout getting any error, so this would also be valid:

将摆脱错误,但不会正确地对孩子进行类型检查。也就是说,您仍然可以传递除TabPropsto以外的子项TabbedView而不会出现任何错误,因此这也是有效的:

return (
  <TabbedView>
    <Tab name="Creatures">
      <div>Creatures!</div>
    </Tab>

    <Tab name="Combat">
        <div>Combat!</div>
    </Tab>

    <NotTabButValidToo />
  </TabbedView>
);

What you could do instead is declare a prop, let's say tabs: TabProps[], to pass down the props you need to create those Tabs, rather than their JSX, and render them inside TabbedView:

你可以做的是声明一个道具,比方说tabs: TabProps[],传递创建这些Tabs所需的道具,而不是它们的 JSX,并将它们呈现在里面TabbedView

interface TabbedViewProps {
  children?: never;
  tabs?: TabProps[];
}

...

const TabbedView: React.FC<TabbedViewProps > = ({ tabs }) => {
  return (
    ...

    { tabs.map(tab => <Tab key={ ... } { ...tab } />) }

    ...
  );
};

回答by Maor Dahan

I tried to assert the type. You can throw or just ignore.

我试图断言类型。您可以抛出或忽略。

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

And in the component itself map the children and assert or ignore

并且在组件本身映射子项并断言或忽略

{React.Children.map(props.children, (tab) => {
  if(tab?.type != Tab) return;
  console.log(tab?.type == Tab);
  return tab;
})}

回答by Moonjsit

Type you are returning in Tab render method is JSX.Element. This is what causes your problem. TabbedView is expecting array of childrens with type Tab. I am not sure if you can specify a certain component as a children type. It can be string or JSX.Element. Can you show the definition file for Tab?

您在 Tab 渲染方法中返回的类型是 JSX.Element。这就是导致您出现问题的原因。TabbedView 期待具有 Tab 类型的儿童数组。我不确定您是否可以将某个组件指定为子类型。它可以是字符串或 JSX.Element。你能显示 Tab 的定义文件吗?

Look at https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.tsto see how JSX.Element interface looks.

查看https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts以了解 JSX.Element 接口的外观。