好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

TypeScript 之 控制流分析(Control Flow Analysis)

控制流分析(Control Flow Analysis)

描述:

CFA 几乎总是采用联合,基于代码逻辑去减少联合里面的类型数量。

大多数时候,CFA 在自然的JavaScript布尔逻辑中工作,但是有一些方法可以定义你自己的函数,这些函数会影响 TypeScript 缩小类型的方式。

简单说就是:根据代码上下文可以推断出当前变量类型。

if 语法(If Statements)

大多数窄化来自 if 语句,用不同类型操作符,在新作用域内进行窄化

typeof (用来判断原始类型)

const input =  getUserInput()
input   //   string | number 
 if  ( typeof  input === "string" ) {
  input   //   string 
}

instanceof (判断构造函数)

const input =  getUserInput()
input   //   string | number[] 
 if  (input  instanceof   Array) {
  input   //   number[] 
}

in (判断属性是否属于对象)

const input =  getUserInput()
input   //   string | {error: ...} 
 if  ("error"  in   input) {
  input   //   {error: ...} 
}

Array.isArray (判断是否为数组)

const input =  getUserInput()
input   //   number | number[] 
 if   (Array.isArray(input)) {
  input   //   number[] 
}

表达式(Expressions)

当进行布尔运算时,窄化也发生在代码的同一行

const input =  getUserInput()
input   //   string | number 
const inputLength = ( typeof  input === "string" && input.length) ||  input
  //   input: string 

识别联合(Discriminated Unions )

type JSONResponse = {status: 200 , data: any}
 | {status: 300 , to: string}
 | {status: 400, error: Error}

所有联合成员都有相同属性名称,CFA(Control Flow Analysis) 能识别对待

const response =  getResponse()
response   //   JSONResponse 

 switch  (response.status) {
    case  200 : response.data
    case  400 : redirect(response.to)
    case  500 : response.error
} 

类型保护(Type Guards)类型谓词(type predicates)

定义用户定义的类型的守卫,只需要定义一个函数返回类型为类型谓词

下面例子中,isFish 就是类型守卫

type Fish = { name: string; swim: () =>  string };
type Bird  = { name: string; fly: () =>  string };
const fish: Fish  = { name: "sharkey", swim: () => 'asd'  }
const bird: Bird  = { name: "noob", fly: () => 'asd'  }

  //   未使用类型谓词 
 function  isFish(pet: Fish |  Bird) {
    return  (pet as Fish).swim !==  undefined;
}
const foo: Fish  | Bird = Math.random() ?  fish : bird;
  if   (isFish(foo)) {
    //   foo: Fish | Bird 
  foo.swim()  //   不能调用,不确定是 Fish 类型 
 }
  //   使用类型谓词 
 function  isFish(pet: Fish |  Bird): pet is Fish {
    return  (pet as Fish).swim !==  undefined;
}
const foo: Fish  | Bird = Math.random() ?  fish : bird;
  if   (isFish(foo)) {
    //   foo: Fish 
  foo.swim()  //   ok 
 }
  //   必须是当前函数签名中参数的名称(pet)。  
//   如果特定类型与原始类型兼容(Fish 与 Fish | Bird),TypeScript 会将该变量缩小为该特定类型,不兼容会报错 

可以使用类型守卫,过滤一个 Fish | Bird 类型数组,并获得一个 Fish 类型数组:

const zoo: (Fish | Bird)[] =  [getSmallPet(), getSmallPet(), getSmallPet()];
const underWater1: Fish[]  =  zoo.filter(isFish);
  //   相当于 
const underWater2: Fish[] =  zoo.filter(isFish) as Fish[];

  //   复杂的例子,谓词需要重复 
const underWater3: Fish[] = zoo.filter((pet): pet is Fish =>  {
    if  (pet.name === "sharkey")  return   false  ;
    return   isFish(pet);
}); 

 断言函数(Assertion Functions)

谓词是,函数返回 true,然后根据代码逻辑在新作用域中表示特定类型

断言函数是抛出,而不是返回 false,然后改变当前作用域表示特定类型

type SuccessResponse =  {data: string}
type ErrorResponse  =  {msg: string}
class JSONResponse implements SuccessResponse {
  constructor(public data: string) { }
}
  function  assertResponse(obj: SuccessResponse |  ErrorResponse): asserts obj is ErrorResponse {
    if  (!(obj  instanceof   JSONResponse)) {
      throw   new  Error("Not a success!" )
  }
}
const res  =  getResponse();
res   //   SuccessResponse | ErrorResponse 
assertResponse(res)  //   断言函数更改当前作用域 
res  //   ErrorResponse 

赋值(Assignment)

使用 "as const" 缩小类型

对象中的属性被视为可变的,在赋值过程中,类型将被“拓宽”为非字面量类型。前缀“as const”将所有类型锁定为它们的字面量类型。

const data1 = { name: "Zagreus"  }
const data2  = { name: "Zagreus"  } as const
  //   data1: {name: string}  
//   data2: { readonly name: "Zagreus"} 

跟踪相关变量

 class SuccessResponse { }
const response  =  getResponse()
const isSuccessResponse  = response  instanceof   SuccessResponse
  if   (isSuccessResponse) {
  response   //   SuccessResponse 
}

重新赋值更新类型

let data: string | number = Math.random() ? "asd" : 123 
data   //   string | number 
data = "hello" 
data   //   string 

 

 

感谢观看,欢迎互相讨论与指导,以下是参考资料链接?

https://www.typescriptlang.org/static/TypeScript%20Control%20Flow%20Analysis-8a549253ad8470850b77c4c5c351d457.png

 

 

 

查看更多关于TypeScript 之 控制流分析(Control Flow Analysis)的详细内容...

  阅读:50次