【发布时间】:2021-04-17 08:27:09
【问题描述】:
我有一个联合类型(在下面的示例中为Pet),它结合了多个对象类型,每个对象类型都有一个type 属性来指示它们的类型。有时我有一个联合类型 (Pet[]) 的数组,需要根据 type 属性对其进行.filter()。这本身工作得很好,但为了避免多余的类型声明,我想确保 .filter() 调用的结果自动正确输入。
User-defined type guards 似乎是解决这个问题的完美解决方案,所以我实现了一个只检查 type 属性并将类型缩小到 { type: 'something' } 显式声明完整类型(这个下面称为isCatLike)。我尝试在if 中使用它,它正确地将我的类型从Pet 缩小到Cat。
然后我尝试将它用作.filter() 的谓词,这一次类型根本没有缩小。结果数组的类型仍然为Pet[],尽管我的if 实验表明类型保护通常能够从Pet 缩小到Cat。
作为另一个实验,我尝试稍微更改类型保护并使类型谓词更加明确(is Cat 而不是is { type: 'cat' },突然.filter() 调用正确地缩小了@的类型 987654343@到Cat[](这个函数下面叫isCat)。
type Cat = { type: 'cat'; name: string; purrs: boolean }
type Dog = { type: 'dog'; name: string; woofs: boolean }
type Pet = Cat | Dog
declare const pets: Pet[]
const isCatLike = (pet: any): pet is { type: 'cat' } => pet.type === 'cat'
const isCat = (pet: Pet): pet is Cat => pet.type === 'cat'
for (const pet of pets) {
if (isCatLike(pet)) {
pet // Cat -> Correct!
}
if (isCat(pet)) {
pet // Cat
}
}
const catLikes = pets.filter(isCatLike)
catLikes // Pet[] -> Incorrect!
const cats = pets.filter(isCat)
cats // Cat[]
Open the example on the TypeScript Playground 自己检查类型。
现在的问题是我不能使用更明确的方法(由 isCat 函数说明),因为我的实际代码在联合中有更多类型,并且谓词也是 由函数 (isType(type: string))。
所以我现在想知道的是:
为什么我的“结构类型保护”在if 语句的上下文中起作用,而不是作为过滤数组的谓词?在这两种情况下它不应该以完全相同的方式工作吗?我做错了什么还是我遇到了类型系统的限制?
【问题讨论】:
标签: typescript types structural-typing