我想创建一个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;
答案 0 :(得分:4)
在TypeScript允许您从联合类型读取name
或color
之前,它需要一些证据证明您使用的是正确的道具类型(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>
)
);
并没有同时props
和 name
都没有理由:
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>;
};