我创建了一个人为的示例( Typescript Playground )来尝试说明我的问题。 foo
、bar
和 baz
是互斥的。我只是在寻找一种将 XYZ 保留为函数参数类型的解决方案。我已经知道 X
类型可以在这里工作。
type X = { foo: string; bar?: undefined; baz?: undefined }
type Y = { foo?: undefined; bar: string; baz?: undefined }
type Z = { foo?: undefined; bar?: undefined; baz: string; }
type XYZ = X | Y | Z;
function foo(xyz: XYZ): string | undefined {
return xyz.foo;
}
理想情况下,我只需要定义所需的部分:
type X = { foo: string };
type Y = { bar: string };
type Z = { baz: string };
但是如果没有冗余,我会收到此错误消息:
Property 'foo' does not exist on type 'XYZ'.
Property 'foo' does not exist on type 'Y'.
我已经尝试过这个,但最终得到的类型看起来像undefined & string
:
type XYZ = { foo?: undefined; bar?: undefined; baz?: undefined } & (X | Y | Z);
最佳答案
我认为您正在寻找 &
( intersection type ),而不是 |
( union type ):
type X = { foo: string };
type Y = { bar: string };
type Z = { baz: string };
type XYZ = X & Y & Z;
来自交叉点类型文档:
An intersection type combines multiple types into one. This allows you to add together existing types to get a single type that has all the features you need. For example,
Person & Serializable & Loggable
is aPerson
andSerializable
andLoggable
. That means an object of this type will have all members of all three types.
也就是说,如果您说当 foo
存在时,bar
和 baz
必须 未定义,我认为你会坚持使用交集类型,但是你必须在使用它之前告诉 TypeScript 你知道 foo 存在,方法是 type assertion 。否则,它无法知道您正在处理的是 X
而不是 Y
或 Z
。例如:
type X = { foo: string };
type Y = { bar: string };
type Z = { baz: string };
type XYZ = X | Y | Z;
function foo(xyz: XYZ): string | undefined {
if ("foo" in xyz) { // Or whatever appropriate check
return (xyz as X).foo;
}
return undefined;
}
我认为没有类型断言就没有办法做到这一点。 (但再说一遍,我不是 Titian Cernicova-Dragomir。:-) )
另一个选择是使用 function overloads ,但您明确表示要保留 XYZ,并且仍然需要您有逻辑来通过类型断言来检测您正在处理的内容。
关于typescript - 删除具有相同形状的类型的冗余,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55168703/