typescript学习-类型推断

109 阅读3分钟

这个博客记录学习typescript类型推断相关的知识总结,根据官方文档理解翻译而来

一、typeof 操作符

typeof用于判断一个原始类型。类型列表如下:

  • "string"
  • "number"
  • "bigint"
  • "boolean"
  • "symbol"
  • "undefined"
  • "object"
  • "function"

因此可以根据这个操作符,确定操作对象属于哪个原始类型

二、‘真值’判断

‘真值’判断简单来说就是利用if语法会将表达式转为布尔值的特性,将if块中的变量类型范围进一步缩小。如下示例:

function printAll(strs: string | string[] | null) {
  if (strs && typeof strs === "object") {
    // 确定类型是string[]
    for (const s of strs) {
      console.log(s);
    }
  } else if (typeof strs === "string") {
    // 确定类型是string
    console.log(strs);
  }
}

这儿需要注意if判断时的隐式转换规则,以下转换皆为false

  • 0
  • NaN
  • "" (the empty string)
  • 0n (the bigint version of zero)
  • null
  • undefined

三、‘等值’判断

‘等值’判断的原理同‘真值’判断,也是利用if语法,但可以通过变量的可能类型集合做一些额外的判断。如下示例:

function example(x: string | number, y: string | boolean) {
  if (x === y) {
    // x与y变量只有一个交集类型string,因此这儿只能是string类型
    x.toUpperCase();  
    y.toLowerCase(); 
  } else {
    console.log(x);        
    console.log(y);      
  }
}

四、in 操作符

in操作符用于判断某个属性是否存在与指定对象中。因此可以通过这个特性进行类型推断,如下示例:

type Fish = { swim: () => void };
type Bird = { fly: () => void };
 
function move(animal: Fish | Bird) {
  if ("swim" in animal) {
   // 有'swim' 只能是Fish类型
    return animal.swim();
  }
  return animal.fly();
}

五、instanceof 操作符

instanceof操作符是用于判断某个对象的原型链上是否存在指定对象的prototype对象(原型对象),因此也可以进行类型推断,示例如下:

function logValue(x: Date | string) {
  if (x instanceof Date) {
    // 此时x是Date类型
    console.log(x.toUTCString());     
  } else {
    console.log(x.toUpperCase());
  }
}

六、类型断言方法

类型断言方法是一种特殊的方法语法形式,用于确定某个变量的类型范围。示例如下:

type Fish = { swim: () => void };
type Bird = { fly: () => void };
declare function getSmallPet(): Fish | Bird;

// 断言方法
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
let pet = getSmallPet();
if (isFish(pet)) {
  // Fish类型
  pet.swim();
} else {
  pet.fly();
}

七、可辨识的联合类型(重要)

当需要依据某个属性来确定某个对象属性什么类型时,可以使用可辨识的联合类型,简要原理在联合类型的所有类型中设置一个共有属性,并且值为字面量,通过这个属性,便可以区分属于哪个类型。示例如下:

interface Circle {
  kind: "circle";
  radius: number;
}
 
interface Square {
  kind: "square";
  sideLength: number;
}
 
type Shape = Circle | Square;

八、穷尽检测法(了解)

这种方法一般用于代码遗漏逻辑的检查,可以算是一种提高代码健壮性的技巧。利用never类型的特性,让typescript类型系统检测出一些未完善的逻辑。示例如下:

interface Circle {
  kind: "circle";
  radius: number;
}
 
interface Square {
  kind: "square";
  sideLength: number;
}
 
type Shape = Circle | Square;
 
function getArea(shape: Shape) {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.sideLength ** 2;
    default:
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}

在上述示例中,代码绝对不会走到default分支,因此default分支的shape对象会被推断为never类型,但当代码扩展,Shape联合的不止2个类型,但在switch中又没对所有的类型进行处理,此时default分支的shape对象不会推断为nerve类型,其他类型不能复制给nerve类型的变量,因此会报错。这就给了开发者一个提示,是否丢失了某些逻辑。