TypeScript类型收缩不适用于联合类型

z0qdvdin  于 2023-05-19  发布在  TypeScript
关注(0)|答案(2)|浏览(236)

为什么类型收缩在这些代码段中不起作用?

const xyz: { num: number } | { str: string }
if ("num" in xyz) {
    xyz // { num: number; } | { str: string; }
}

我甚至尝试添加一个类型判别式:

const xyz: { type: "num", num: number } | { type: "str", str: string }
if (xyz.type === "num") {
    xyz // { type: "num", num: number } | { type: "str", str: string }
}

我使用的是Typescript版本5.0.2

7hiiyaii

7hiiyaii1#

看起来当Typescript类型检查器抱怨先前的错误或警告时,可能会抛出正确的类型收缩。
在我的例子中,解决方案是修复(或静默)未初始化变量xyz的使用(以及其他先前的类型错误),类型收缩再次正常工作。
看似无关的类型错误会使类型检查器处于糟糕的状态;确保在处理任何奇怪的错误之前先修复简单的错误。

ijnw1ujt

ijnw1ujt2#

类型窄化在示例中不起作用,因为{ num: number } | { str: string } and { type: "num", num: number } | { type: "str", str: string }的类型联合不是互斥的,这意味着该类型的变量可以具有属于两个联合成员的属性。
在第一个示例中,即使您检查了xyz中的“num”,xyz仍然可以是{ str: string }类型。这是因为xyz可以有属性str:字符串,它是第二个联合成员的成员。
类似地,在第二个示例中,检查xyz.type === "num"仅将类型缩小到{ type: "num", num: number } | { type: "str", str: string },而不是特定类型。因此,xyz仍然可以具有属性str: string
要在这些示例中进行类型收缩,需要使用类型保护,它可以将类型缩小到联合体的特定成员。例如,你可以像这样定义一个自定义类型保护函数:

function isNum(obj: { num?: unknown }): obj is { num: number } {
  return typeof obj.num === "number";
}

然后你可以在代码中使用这个类型保护来缩小xyz的类型:

const xyz: { num: number } | { str: string } = { num: 42 };
if (isNum(xyz)) {
  xyz // { num: number }
}

类似地,对于第二个例子,你可以像这样定义一个类型保护函数:

function isNum(obj: { type?: unknown }): obj is { type: "num", num: number } {
  return obj.type === "num";
}

然后你可以在代码中使用这个类型保护来缩小xyz的类型:

const xyz: { type: "num", num: number } | { type: "str", str: string } = { type: "num", num: 42 };
if (isNum(xyz)) {
  xyz // { type: "num", num: number }
}

相关问题