受歧视联合仅适用于文字类型吗?

Dev*_*per 5 typescript

在下面的代码片段中,我无法使用typeof运算符来区分联合类型。

function f(arg: { status: number; one: boolean } | { status: string; two: boolean }) {
    if (typeof arg.status === "number") {
        return arg // arg is still of the union type and is not narrowed
    } else {
        return arg // similar here
    }
}
Run Code Online (Sandbox Code Playgroud)

但如果status改为某种文字类型,那么联合体就可以被区分。

function f(arg: { status: "one"; one: boolean } | { status: "two"; two: boolean }) {
    if (arg.status=== "one") {
        return arg // here arg is of type { status: "one"; one: boolean }
    } else {
        return arg // and here it's of type { status: "two"; two: boolean }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,我想知道为什么它在第一种情况下不起作用,是受歧视的联合仅适用于文字类型还是还有其他原因?

我试图在文档中查找是否在某个地方提到了歧视联合仅适用于文字类型,但我找不到任何内容。

链接到游乐场

Mah*_*ary 2

嗯,这是 Typescript 目前的一个限制。它已在 Typescript Github存储库中讨论过几次,因此我将使用其中的一些响应。

首先,您应该知道

类型保护不会将类型缩小传播到父对象。缩小仅在访问缩小属性时应用,这就是破坏函数起作用但引用函数不起作用的原因。缩小母体范围将涉及合成新类型,这将是昂贵的。

所以基本上如果您使用下面的代码,您会发现 TS 确实能够缩小该特定属性的类型:

function f1(arg: { status: number; one: boolean } | { status: string; two: boolean }) {
    if (typeof arg.status === "number") {
        const st = arg.status // st: number
    }
}
Run Code Online (Sandbox Code Playgroud)

仅在特定情况下(当属性被视为联合的判别式时)才会缩小父对象的范围。如果满足以下条件,则将属性视为判别属性:

1- 该属性是文字类型,如可区分的联合类型所述。

2- 如果联合类型的 a 属性具有包含至少一个单元类型且没有可实例化类型的联合类型,则该联合类型的属性将成为判别式属性,如此处所述允许联合判别式中的非单元类型

欲了解更多信息,您可以查看此处此处