Appearance
使用类型谓词
到目前为止,我们已经用现有的JavaScript结构来处理窄化问题,然而有时你想更直接地控制整个代码中的类型变化。 为了定义一个用户定义的类型保护,我们只需要定义一个函数,其返回类型是一个类型谓词。
typescript
type Fish = {
name: string
swim: () => void
}
type Bird = {
name: string
fly: () => void
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined
}
在这个例子中, pet is Fish 是我们的类型谓词。谓词的形式是 parameterName is Type ,其中 parameterName 必须是当前函数签名中的参数名称。
任何时候 isFish 被调用时,如果原始类型是兼容的,TypeScript将把该变量缩小到该特定类型。
typescript
function getSmallPet(): Fish | Bird {
let fish: Fish = {
name: 'gold fish',
swim: () => { }
}
let bird: Bird = {
name: 'sparrow',
fly: () => { }
}
return true ? bird : fish
}
// 这里 pet 的 swim 和 fly 都可以访问了
let pet = getSmallPet()
if (isFish(pet)) {
pet.swim()
} else {
pet.fly()
}
注意,TypeScript不仅知道 pet 在 if 分支中是一条鱼;它还知道在 else 分支中,你没有一条 Fish ,所以你一定有一只 Bird 。
你可以使用类型守卫 isFish 来过滤 Fish | Bird 的数组,获得 Fish 的数组。
typescript
const zoo: (Fish | Bird)[] = [getSmallPet(), getSmallPet(), getSmallPet()]
const underWater1: Fish[] = zoo.filter(isFish)
// 或者,等同于
const underWater2: Fish[] = zoo.filter(isFish) as Fish[]
// 对于更复杂的例子,该谓词可能需要重复使用
const underWatch3: Fish[] = zoo.filter((pet): pet is Fish => {
if (pet.name === 'frog') {
return false
}
return isFish(pet)
})