TypeScript 将倾向于子类型缩减的并集缩小到其最窄组成元素

9avjhtql  于 2022-10-29  发布在  TypeScript
关注(0)|答案(6)|浏览(200)

错误报告

类型缩小似乎没有考虑到我为确保变量具有正确的类型而进行的赋值。
(评论)评论文章

🔎检索词

类型收缩赋值

🕗版本和回归信息

4.5.4

  • 这是我尝试的每个版本中的行为,我查看了关于“类型缩小”条目的常见问题解答

Playground链接

Playground链接

💻代码

declare let a: object | any[] | undefined

if (a === undefined) {
    a = [] // I expect this line to have TS understand that a is any[] from now on
} else if (!Array.isArray(a)) {
    throw new Error()
}
[...a] // complains here because a is object | any[]

🙁实际行为

a的类型为object | any[]

🙂预期行为

a转换为any[]类型

lmyy7pcs

lmyy7pcs1#

这是预料之中的;数组可分配给object

31moq8wy

31moq8wy2#

@fatcerberus虽然可能是这样,但我不认为这会让它变得不那么出人意料?
或者,既然我显式地传递了一个数组,那么类型化应该缩小到这个范围,我的期望是错误的吗?
我尝试了a = [] as consta = [] as any[],仍然得到同样的问题,这真的感觉违反直觉。

5ssjco0h

5ssjco0h3#

[]是一个有效的any[] * 和 * 一个有效的object。因此TS不能缩小object的范围。你错误地认为object意味着“任何非数组对象”,但它实际上意味着“任何对象”。事实上,因为objectany[]的 * 超类型 *,编译器完全有权利 * 完全忽略 * 联合体的any[]部分,在某些情况下它会这样做(称为子类型约简):

一般来说,在联合中有重叠的类型会给予你带来麻烦。

slsn1g29

slsn1g294#

你可以写

declare let a: { push?: never } | any[] | undefined

if (a === undefined) {
    a = [] // I expect this line to have TS understand that a is any[] from now on
} else if (!Array.isArray(a)) {
    throw new Error()
}

减少子类型的联合并不好,但似乎我们可以修复赋值限制逻辑,对任何结果联合进行子类型减少,因为这肯定是可靠的。

6ovsh4lw

6ovsh4lw5#

您错误地认为object表示“任何非数组对象”,但实际上它表示“任何对象”。
@fatcerberus我非常理解这一点,因此我们可以做以下事情:

const b: any[] = []
const c: object = b

我认为不符合人机工程学的是没有将类型缩小到显式分配的类型:

let d: object | any[] | undefined
d = []
takeArray(d) // should work, currently doesn't

但@RyanCavanaugh的建议奏效了!

let d: { push?: never } | any[] | undefined
d = []
takeArray(d) // works

@fatcerberus谢谢你解释TypeScript目前是如何看待这种情况的,但不管它做了什么,我的问题是,也许会有一些改变,使它更符合人体工程学。

gxwragnw

gxwragnw6#

我的问题是,也许会有一些改变,使它更符合人体工程学
确实如此,我同意这是不符合人体工程学的。注意@RyanCavanaugh对这个问题的重命名是解决这个问题的一种方法。只是你把这个作为bug报告发布,而观察到的行为实际上是自然地福尔斯了类型系统的规则。所以这看起来像是个误会我想澄清一下(因为修复这个问题会给类型推断/收缩添加另一个特别的规则,它不是纯粹基于可赋值性的,而且TS中的IMO类型推断太特别了)。显然Ryan同意你的观点,这是一个bug,所以......是的😛

相关问题