使用两个不同的prop接口来响应TypeScript组件

时间:2019-10-30 17:24:53

标签: reactjs typescript

我想创建一个React TypeScript组件,其props是两个不同接口的结合。但是,这样做时,我会收到警告:

TS2339: Property 'color' does not exist on type 'PropsWithChildren<Props>'

如何创建带有两个不同prop接口的并集的React TypeScript组件,并同时能够解构这些prop?谢谢!

sampleComponent.tsx:

import * as React from 'react';

interface SamplePropsOne {
  name: string;
}

interface SamplePropsTwo {
  color: string;
}

type Props = SamplePropsOne | SamplePropsTwo;

const SampleComponent: React.FC<Props> = ({ color, name }) => (
  color ? (
    <h1>{color}</h1>
  ) : (
    <h1>{name}</h1>
  )
);

export default SampleComponent;

enter image description here

2 个答案:

答案 0 :(得分:4)

在TypeScript允许您从联合类型读取namecolor之前,它需要一些证据证明您使用的是正确的道具类型(SamplePropsOne或{{1 }}。有几种标准的方法可以提供此功能。

一种方法是通过引入属性来区分工会的分支,从而使工会成为带有 tagged 标签的工会。这种类型的检查就可以了:

SamplePropsTwo

如果您把情况弄倒了(就像我写这篇文章时一样!),那么TypeScript会抱怨。

如果属性的存在足以区分类型,则可以使用interface SamplePropsOne { type: 'one'; name: string; } interface SamplePropsTwo { type: 'two'; color: string; } type Props = SamplePropsOne | SamplePropsTwo; const SampleComponent: React.FC<Props> = props => ( props.type === 'one' ? ( <h1>{props.name}</h1> ) : ( <h1>{props.color}</h1> ) ); 运算符:

in

如果要确定您拥有的对象类型需要更复杂的逻辑,则可以编写user-defined type guard。关键部分是返回类型中的“是”:

interface SamplePropsOne {
  name: string;
}
interface SamplePropsTwo {
  color: string;
}
type Props = SamplePropsOne | SamplePropsTwo;

const SampleComponent: React.FC<Props> = props => (
  'color' in props ? (
    <h1>{props.color}</h1>
  ) : (
    <h1>{props.name}</h1>
  )
);

还值得注意的是,由于结构化类型的工作方式,因此在您的示例中function isSampleOne(props: Props): props is SamplePropsOne { return 'name' in props; } const SampleComponent: React.FC<Props> = props => ( isSampleOne(props) ? ( <h1>{props.name}</h1> ) : ( <h1>{props.color}</h1> ) ); 并没有同时propsname都没有理由:

color

如果不允许这样做很重要,则需要使用一些更高级的类型:

const el = <SampleComponent name="roses" color="red" />;  // ok

ts-essentials库具有一个XOR generic,可用于帮助构建像这样的排他联合。

答案 1 :(得分:1)

我认为您正在寻找的是intersection types

替换此行:

type Props = SamplePropsOne | SamplePropsTwo;

有这行:

type Props = SamplePropsOne & SamplePropsTwo;
  • 交叉点类型:将多个接口/类型组合为一个

  • 联合类型:选择多种接口/类型之一

编辑

我想要的是不可能的。您可以做的是在投射props之后在一行中分解每种类型:

const SampleComponent: React.FC<Props> = props => {
  const { name } = props as SamplePropsOne;
  const { color } = props as SamplePropsTwo;

  return color ? <h1>{color}</h1> : <h1>{name}</h1>;
};