🔎 搜索词
- 区分工会,"discriminated-unions"
- "对象中键为数字", "number key"
- "类型保护"
🕗 版本与回归信息
- 这是一次崩溃
⏯ Playground链接
https://www.typescriptlang.org/play?#code/C4TwDgpgBAglC8UB2BXAtgIwgJwNoF0oAfKAZ2GwEskBzAgKHtEigCEEoBvKABgC5k6LNgA0UAIYCAjFAC+xLrwHkqtMZKgByKZrmMAJhADGAG3HZoRgPZJyEgTHqHT5yzbsYBrRpQBmUAApmCCt-cVweQnhorVRMHE0ASi56KDSoa1srEwgAOhMrGgDxRNT0gHpy9Or0gD0AfnpZej9A4NCoDFxNcU0omM044SSU6szSbLyCooxS6sqamoamlv8g8BD-Ls0ePoQBoYTkzjK08cn8woDZ06gFxbrG5tb1yA6uyP3EQaEj0fTzjlLjM5hUqg80stmkA
💻 代码
type A = number[] | string[]
type B = { 0: number, a: 1 } | { 0: string, a: '1' }
declare const a: A
declare const b: B
if (typeof a[0] === 'number') {
console.log(a)
// ^? A
}
if (typeof b['a'] === 'number') {
console.log(b)
// ^? { 0: number, a: 1 }
}
if (typeof b['0'] === 'number') {
console.log(b)
// ^? B
}
if (typeof b[0] === 'number') {
console.log(b)
// ^? B
}
🙁 实际行为
无法将 b
作为联合类型 B
的选项进行类型保护。
🙂 预期行为
在用 typeof b['0'] === 'number'
对 b
进行类型保护时,将其视为 { 0: number, a: 1 }
。
9条答案
按热度按时间8wtpewkr1#
文档似乎没有规定键必须是字符串。
z9gpfhce2#
这与键是否为字符串无关-判别式必须是字面类型的。
number
和string
不是有效的判别式,而且也无法通过typeof
进行判别式检查。gev0vcfq3#
typeof
在某些情况下可以工作,但我完全不理解它。0dxa2lsx4#
?????????????????
b1zrtrql5#
看起来只有特定的联合类型会触发这个bug。在这个例子中,只有数字和字符串的联合触发了bug,可能是因为它被推断为
number | string
。当我将其更改为另一个基本类型的联合或字面量类型时,Discriminated 可以成功工作。bvjxkvbb6#
boolean
在内部被视为true | false
,它是字面类型的,并使属性具有区分性。sg24os4d7#
这是我第一次看到
typeof
可以用于缩小一个被区分的联合体。这是一种高度非正统的做法(在这种情况下,甚至具有误导性)。维护者一直说,被区分的联合体缩小只适用于直接值比较(即x[0] === 'foo'
)。h7wcgrx38#
通过在区分联合体上使用类型缩小是通过寻找看起来像判别属性的属性来实现的...但是
string[]
和number[]
没有这样的属性!这是可以做到的,但现在还不是正确的方法。0g0grzrc9#
这里有一个奇怪的现象,如果不是
union type
只有string[]
的情况,这个问题有一个部分解。Playground Link
如果我们用
string[]
替换boolean[]
,那么就会产生一个问题。Playground Link