七天学习TypeScript(二)

171 阅读2分钟

一、引言

  昨天的文章七天学TypeScript(一) 是TypeScript的常用类型和基本使用。浏览一遍TypeScript的手册就会发现,TypeScript学习最重要的有三点:类型,类型,类型! 除了类型使用,当然还有类型安全。另外,本系列文章不求面面俱到,每篇说清楚一件事就很不错了,所以今天主要说类型收窄。对于类型收窄,我的理解是TypeScript根据编程语句上下文对变量或表达式的类型进行推断,从而和类型检查、bug检查相结合,尽可能明确语义,减少bug。

1、先学习字面量类型。 const声明的或用联合赋值的类型是字面量类型,不同于var或者let声明的具体类型。

  • 例子:

    function printText(s: string, alignment: "left" | "right" | "center") {
      // ...
    }
    ​
    printText("Hello, world", "left");
    //报错,传递的centre是字符串,不是字面量(center才行)
    printText("G'day, mate", "centre"); 
    

2、枚举类型,一般高级语言都有,这里就直接举例了。

  • 例子:

    enum UserResponse {
      No = 0,
      Yes = 1,
    }
    ​
    function respond(recipient: string, message: UserResponse): void {
      // ...
    ​
    }
    respond("Princess Caroline", UserResponse.Yes);
    ​
    //再如:
    enum Direction {
      Up = "UP",
      Down = "DOWN",
      Left = "LEFT",
      Right = "RIGHT",
    }
    

二、类型收窄的N个方式

1、用typeof进行类型守护 。

  • 例子:

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

2、布尔判断类型收窄,通常是if/else的条件判断

  • 例子:

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

3、等值判断类型收窄,常用的等值判断大家都知道,有:===,!==,==, and!=

  • 例子:

    function printAll(strs: string | string[] | null) {
      if (strs !== null) {
        if (typeof strs === "object") {
          //参数strs是 string[]
          for (const s of strs) { 
            console.log(s);
          }
        } else if (typeof strs === "string") {
          //参数strs是 string
          console.log(strs);
        }
      }
    }
    

4、in 操作符收窄

  • 例子:

    type Fish = { swim: () => void };
    type Bird = { fly: () => void };
     
    function move(animal: Fish | Bird) {
      if ("swim" in animal) {
        return animal.swim();
      }
     
      return animal.fly();
    }
    

5、instanceof 收窄。

  • 例子:

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

6、赋值收窄。

  • 例子:

    let x = Math.random() < 0.5 ? 10 : "hello world!";
    let x: string | number
    //因为是string和number的联合类型,所以此处赋值为number没问题
    x = 1;
    console.log(x);
    ​
    //报错,赋值为布尔型
    x = true; 
    console.log(x);
    

7、复杂类型可以通过类型谓词

  • 例子

    //pet is Fish 就是类型谓词断定
    function isFish(pet: Fish | Bird): pet is Fish {
      return (pet as Fish).swim !== undefined;
    }
    

8、一个复杂类型判断的最佳实践,是通过共同属性判断类型。

  • 例子

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

9、switch中注意never类型

  • 例子

    //(1)来一个计算面积的函数,开始支持Circle和Square
    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;
      }
    }
    ​
    ​
    //(2)以后业务需要,增加了Triangle接口后会原方法会报错
    interface Triangle {
      kind: "triangle";
      sideLength: number;
    }
     
    type Shape = Circle | Square | Triangle;
     
    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;
          //报错:Triangle 不能赋值给never
          return _exhaustiveCheck;
      }
    }     
    

注意:never可以赋值给别的类型;别人不能赋值给它,除非never赋值给never。

明天继续学习函数和对象类型,待续。

如果有错误或表述不清之处也请大家多批评指正。参考网址:www.typescriptlang.org