TypeScript 类型收窄

sankigan2021-4-23前端TypeScript

TypeScript の Narrowing

TypeScript 的类型检查器会考虑到这些类型保护和赋值语句,而这个将类型推导为更精确类型的过程,我们称之为收窄(narrowing)

// Case1
function padLeft(padding: number | string, input: string) {
  if (typeof padding === 'number') {
    return new Array(padding + 1).join(' ') + input;
  }
  return padding + input;
}

typeof 类型保护 (type guards)

真值收窄 (Truthiness narrowing)

等值收窄 (Equality narrowing)

in 操作符收窄

instanceof 收窄

赋值语句

控制流分析 (Control flow analysis)

在 Case1 中,第一个 if 语句,因为有 return 语句,TypeScript 就能通过代码分析,判断出在剩余的部分 return padding + input,如果 padding 是 number 类型,是无法达到 (unreachable) 这里的,所以在剩余的部分,就会将 number 类型从 number | string 类型中删除掉。

这种基于**可达性(reachability)**的代码分析就叫做控制流分析(Control flow analysis)。在遇到类型保护和赋值语句的时候,TypeScript 就是使用这样的方式收窄类型。而使用这种方式,一个变量可以被观察到变为不同的类型:

类型判断式 (type predicates)

如果你想直接通过代码控制类型的改变,你可以自定义一个类型保护。实现方式是定义一个函数,这个函数返回的类型是类型判断式:

function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

在上面这个例子中,pet is fish 就是我们的类型判断式,一个类型判断式采用 parameterName is Type 的形式,但 parameterName 必须是当前函数的参数名。

当 isFish 被传入变量进行调用,TypeScript 就可以将这个变量收窄到更具体的类型:

let pet = getSmallPet();

if (isFish(pet)) {
  pet.swim();
} else {
  pet.fly();
}