Skip to content

使用类型谓词

到目前为止,我们已经用现有的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) 
})