我创建了一个功能组件,看起来像这样:
type RootComponentProps = {
propThatAlwaysExists: string;
};
type ComponentPropsV1 = {
type: "v1";
onlyOnV1: string;
onlyOnV2?: never;
};
type ComponentPropsV2 = {
type: "v2";
onlyOnV1?: never;
onlyOnV2: string;
};
type ComponentProps = RootComponentProps & (
| ComponentPropsV1
| ComponentPropsV2
);
export const Component: FC<ComponentProps> = ({
propThatAlwaysExists,
type,
onlyOnV1,
onlyOnV2,
}) => {
// do typechecked things, no errors in component body
};
prop?: never
类型是我学到的一种允许解构props的技巧,因为TypeScript禁止直接访问任何不***绝对保证***存在的属性,但解构是eslint
等代码正确性工具的首选prop访问方法,在我看来,一般来说,代码可读性。
然后,我尝试将这个组件挂载到它的父组件中,父组件会传递大部分这些属性。我最初尝试明确地写出父项:
import { Component } from "./Component";
type RootParentComponentProps = {
label: string;
propThatAlwaysExists: string;
};
type ParentComponentPropsV1 = {
type: "v1";
onlyOnV1: string;
onlyOnV2?: never;
};
type ParentComponentPropsV2 = {
type: "v2";
onlyOnV1?: never;
onlyOnV2: string;
};
type ParentComponentProps = RootParentComponentProps & (
| ParentComponentPropsV1
| ParentComponentPropsV2
);
export const ParentComponent: FC<ParentComponentProps> = ({
label,
type,
onlyOnV1,
onlyOnV2,
}) => {
// some effects, yadda yadda
return (
<div>
<span>{label}</span>
<Component
propThatAlwaysExists={propThatAlwaysExists}
type={type}
onlyOnV1={onlyOnV1}
onlyOnV2={onlyOnV2}
/>
</div>
);
};
但我得到了一个非常奇怪的错误:
Types of property 'onlyOnV1' are incompatible.
Type 'string | undefined' is not assignable to type 'undefined'.
Type 'string' is not assignable to type 'undefined'.ts(2322)
我想这可能是因为TS无法确定类型之间的相同排除,并且意识到我可以干燥一些代码,所以我将ParentComponent
的类型定义更改为:
import { Component, ComponentProps } from "./Component";
type RootParentComponentProps = {
label: string;
};
type ParentComponentProps = RootParentComponentProps & ComponentProps;
然而,错误仍然没有改变。
在这一点上,我认为问题可能是TypeScript实际上失去了属性排他性的上下文,和/或never
的严格性实际上意味着never
,所以我通过指定onlyOnV1
和onlyOnV2
创建了一个不可能的props安排,当我创建的联合类型实际上说只有一个属性可以存在时。
为了解决这个问题,我尝试将Component
的独占类型从
type ComponentPropsV1 = {
type: "v1";
onlyOnV1: string;
onlyOnV2?: never;
};
type ComponentPropsV2 = {
type: "v2";
onlyOnV1?: never;
onlyOnV2: string;
};
至
type ComponentPropsV1 = {
type: "v1";
onlyOnV1: string;
onlyOnV2: undefined;
};
type ComponentPropsV2 = {
type: "v2";
onlyOnV1: undefined;
onlyOnV2: string;
};
但是错误仍然没有改变,这对我来说就没有意义了。据我所知,这些都是真的:
- TypeScript从
ComponentProps
的类型中知道onlyOnV1
和onlyOnV2
具有反向互斥类型,其中如果一个是string
,则另一个必须是undefined
,反之亦然 - 从
ParentComponent
传递到Component
的类型***完全***是ComponentProps
的类型
然而,不知何故,TypeScript发明了一种场景,其中独占联合类型从
{
type: "v1";
onlyOnV1: string;
onlyOnV2: undefined;
} | {
type: "v2";
onlyOnV1: undefined;
onlyOnV2: string;
}
至
{
type: "v1" | "v2";
onlyOnV1: string | undefined;
onlyOnV2: string | undefined;
}
为了对ComponentProps
进行类型检查,即使它实际上是ComponentProps
。
我是否错误地使用和/或设计了我的联合类型?
有没有什么方法可以在不牺牲Component
或ParentComponent
的显式性的情况下完成这项工作?
2条答案
按热度按时间brgchamk1#
Typescript做了预期的事情;因为你破坏了 prop ,
type
可以是v1
或v2
;这就是为什么你得到错误。有两种选择:选项1,不析构props
并传递整个对象:选项2,显式检查
type
的值:Playground
vwkv1x7d2#
在尝试wonderflame's answer没有成功之后,我意识到我的“最小可重复示例”实际上过于简化了-这里没有描绘的是TypeScript内置
Omit<T, U>
类型的间隙使用,它允许您从对象中敲击键。Omit
负责类型扩展,因为当简单对象Map类型在复合类型上运行时,复合类型似乎会组合在一起。为了解决这个问题,我必须更明确地说明我的Component
props,因为它们是从父对象传递过来的,***和***传播了用于Component的props,改变了这一点-到这个