【发布时间】:2020-04-09 07:16:05
【问题描述】:
在下面的代码中,为什么typeof data.x === 'string'类型守卫不足以区分联合类型?
interface A { x: string, y: number }
interface B { x: number, y: string }
function handler(data: A | B) {
if (typeof data.x === 'string') {
data.y // string | number --- WHUT?
}
}
在什么情况下可以使用(无效)形状{ x: string: y: string } 调用handler?
使用判别式,它可以工作(为什么?):
interface A { kind: 'A', x: string, y: number }
interface B { kind: 'B', x: number, y: string }
function handler(data: A | B) {
if (data.kind === 'A') {
data.y // number
}
}
阅读Discriminated Unions 上的官方文档没有帮助。
他们只声明:
某些语言会自动为您区分工会;相反,TypeScript 建立在现有的 JavaScript 模式之上。
这并不能解释为什么 TS 在某些情况下可以使用类似的类型保护,而在联合的情况下却不能(我在第一个示例中没有看到任何歧义)。
【问题讨论】:
-
判别式应该是 unique:在正确的示例中,您使用字符串文字 'A' 和 'B' 但在原始示例中(如果您正在考虑x 属性作为判别式)您只是使用字符串。换句话说,您的第一个示例实际上不是 TS 类型系统中的可区分联合。
-
我知道这不是一个有区别的联合(根据定义,它需要一个判别式)。我的问题是,为什么它需要一个 - 即为什么我需要使它成为一个受歧视的工会?为什么我原来的类型保护还不够?
-
只有区分联合才能让您通过检查其属性之一将联合类型的对象缩小到其组成部分之一的对象。您正试图通过检查
x属性将A | B缩小到A,该属性仅在A | B是可区分的联合并且x是其判别式时才有效。但他们不是,所以你不能。 -
是的,但这是循环推理。 true answer is --- 由于动机/时间/性能限制,而不是健全性,它没有实现。
-
我认为这里的沟通问题是因为你在问“为什么我需要把它变成一个有歧视的工会?”而不是“为什么 TS 不认为这是一个受歧视的工会?”前一个问题会邀请诸如“您想要一个受歧视的工会,因为您试图根据其属性之一来区分工会;这就是受歧视的工会是”之类的答案,而后一个问题会邀请诸如“缺乏执行这种特定模式的表现/动力/时间”。
标签: typescript discriminated-union union-types