[英]React TypeScript component with two different prop interfaces
我想创建一个 React TypeScript 组件,其 props 是两个不同接口的联合。 但是,当我这样做时,我会收到警告:
TS2339: Property 'color' does not exist on type 'PropsWithChildren<Props>'
如何创建一个 React TypeScript 组件并结合两个不同的道具接口,同时能够解构这些道具? 谢谢!
示例组件.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;
在 TypeScript 让您从联合类型中读取name
或color
之前,它需要一些证据证明您正在使用正确类型的道具( SamplePropsOne
或SamplePropsTwo
)。 有一些标准方法可以提供它。
一种是通过引入一个属性来区分联合的分支,从而使联合成为标记联合。 这种类型检查就好了:
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>
)
);
如果你把案例倒过来(就像我在写这篇文章时所做的那样),那么 TypeScript 会抱怨。
如果某个属性的存在足以区分类型,那么您可以使用in
运算符:
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>
)
);
如果确定您拥有哪种类型的 object 需要更复杂的逻辑,您可以编写用户定义的类型保护。 关键部分是返回类型中的“is”:
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
如果不允许这样做很重要,您将需要使用一些稍微花哨的类型:
interface SamplePropsOne {
name: string;
color?: never;
}
interface SamplePropsTwo {
color: string;
name?: never;
}
type Props = SamplePropsOne | SamplePropsTwo;
ts-essentials 库有一个XOR
泛型,可用于帮助构建这样的排他联合。
我认为您正在寻找的是交叉点类型。
替换这一行:
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>;
};
我认为这会有所帮助
interface SamplePropsOne {
name: string;
color: never;
}
interface SamplePropsTwo {
name: never;
color: string;
}
type Props = SamplePropsOne | SamplePropsTwo;
const SampleComponent = ({ color, name }: Props) => {
console.log(color ? color : name);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.