TypeScript学习(二):Handbook -> Narrowing

1,052 阅读2分钟

type guard

对于联合类型,需要进行类型收窄。此时需要 if 或者 typeof 对类型进行收窄,进行类型守卫。

typeof

typeof 操作符可以得到值的基础类型,如,string,number,bigint,boolean,symbol,undefined,object,function。但是,没有 null。

TS会再次校验typeofd返回值,这也是一种 type guard。

如下,虽然使用 typeof 收窄了类型,但是 JavaScritp 中 null 是一个object,TypeScript也会提示报错。

// @errors: 2531
function printAll(strs: string | string[] | null) {  
  if (typeof strs === "object") {    
    for (const s of strs) {
    //Object is possibly 'null'.Object is possibly 'null'.      
    console.log(s);    
     } 
   } 
   else if (typeof strs === "string") {    
   console.log(strs);  
} else {    
// do nothing 
 }}

TS 只是把 strs 类型收窄成了 string[] | null。

Truthiness narrowing

TypeScript 只会帮助我们进行类型检查,如果在类型收窄时不留意变量的,那么在JS运行中,就可能会隐藏bug了。

function printAll(strs: string | string[] | null) {
  // !!!!!!!!!!!!!!!!  
  //  DON'T DO THIS! 
  //   KEEP READING  
  // !!!!!!!!!!!!!!!!  
  if (strs) {    
    if (typeof strs === "object") {      
      for (const s of strs) {        
        console.log(s);      
        }    
      } 
     else if (typeof strs === "string") {      
       console.log(strs);    
     }  
    }
  }

in 操作符

type Fish = { swim: () => void };
type Bird = { fly: () => void };
type Human = {  swim?: () => void, fly?: () => void };
function move(animal: Fish | Bird | Human) {  
  if ("swim" in animal) {     
    // animal      (parameter) animal: Fish | Human
  } else {    
    // animal      (parameter) animal: Bird | Human
  }
}

instanceof 操作符

也会进行类型收窄

赋值

Control flow analysis

This analysis of code based on reachability is called control flow analysis。TS 会基于此,即,TS会对在不同分支逻辑中的变量进行分析,从而类型收窄。

类型预测

parameterName is Type, 同时 parameterName必须是函数签名中形参的名称。

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

TODO

对于 class,可以使用 this is Type 进行类型收窄

www.typescriptlang.org/docs/handbo…

可辨识联合 -> Discriminated unions

```TypeScript```

interface Shape {  kind: "circle" | "square";  radius?: number;
  sideLength?: number;}// 虽然利用 === 对 kind 进行了类型收窄,但是得用 ! 来"证实" shape.radius 一定存在
function getArea(shape: Shape) {  if (shape.kind === "circle") {    return Math.PI * shape.radius! ** 2;  }}
// 优化一下 利用字面量类型与联合类型进行收窄
interface Circle {  kind: "circle";  radius: number;}
interface Square {  kind: "square";  sideLength: number;}type Shape = Circle | Square;

// 优化function getArea(shape: Shape) {  if (shape.kind === "circle") {    return Math.PI * shape.radius ** 2;  }}

never 类型

在类型收窄时,可以降低联合类型的选项。当收窄到一点的时候,已经除去了所有的可能性,应该没有任何类型剩余。在TS中,never表示一种不应该存在的状态。

never类型可以赋值给任何类型,但是只有never类型可以赋值给never类型。

Exhaustiveness checking

通过never类型,确保代码联合类型变动之后,所有的类型都被穷尽了。预防bug。

详见:www.zhihu.com/question/35…