二、ts官网-类型缩小 笔记

类型缩小

TypeScript 遵循我们的程序可以采用的可能执行路径来分析给定位置的值的最具体的可能类型。它着眼于这些特殊检查(称为类型保护)和赋值,将类型精炼为比声明的更具体的类型的过程称为缩小。

function padLeft(padding: number | string, input: string): string {
  if (typeof padding === "number") {
    return " ".repeat(padding) + input;                  
    //(parameter) padding: number
  }
  return padding + input;       
  //(parameter) padding: string
}

TypeScript 可以理解几种不同的结构来缩小类型。


typeof 类型保护

支持 typeof 运算符: TypeScript 可以理解它来缩小不同分支中的类型。

  • “string”
  • “number”
  • “bigint”
  • “boolean”
  • “symbol”
  • “undefined”
  • “object”
  • “function”

注意在上面的列表中,typeof 不返回字符串 null


真值缩小

我们可以在条件、&&、||、if 语句、布尔否定 (!) 等中使用任何表达式

function getUsersOnlineMessage(numUsersOnline: number) {
  if (numUsersOnline) {
    return `There are ${numUsersOnline} online now!`;
  }
  return "Nobody's here. :(";
}

像 if 这样的构造首先将它们的条件 “强制转换” 到 boolean 来理解它们,然后根据结果是 true 还是 false 来选择它们的分支

  • 0
  • NaN
  • “” (空字符串)
  • 0n(bigint版本零)
  • null
  • undefined

以上全部强制转换为 false,其他值强制转换为 true

相等性缩小

使用 switch 语句和 =、!、== 和 != 等相等性检查来缩小类型

function example(x: string | number, y: string | boolean) {
  if (x === y) {
    // We can now call any 'string' method on 'x' or 'y'.
    x.toUpperCase();
	//(method) String.toUpperCase(): string
	
    y.toLowerCase();
	//(method) String.toLowerCase(): string
  } else {
    console.log(x);
	//(parameter) x: string | number
	
    console.log(y);           
	//(parameter) y: string | boolean
  }
}

in 运算符缩小

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 缩小

instanceof:用于检查一个值是否是另一个值的 “instance”

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

赋值

当我们为任何变量赋值时,TypeScript 会查看赋值的右侧并适当地缩小左侧

let x = Math.random() < 0.5 ? 10 : "hello world!";
   
let x: string | number

x = 1;
console.log(x);
      //let x: number
x = "goodbye!";
console.log(x);
     //let x: string
x = true;
// Type 'boolean' is not assignable to type 'string | number'.

控制流分析

控制流分析:基于可达性的代码分析称为控制流分析

控制流可以一次又一次地分裂和重新合并,并且可以观察到该变量在每个点具有不同的类型

function example() {
  let x: string | number | boolean;
 
  x = Math.random() < 0.5;
 
  console.log(x);
             
let x: boolean
 
  if (Math.random() < 0.5) {
    x = "hello";
    console.log(x);
               
let x: string
  } else {
    x = 100;
    console.log(x);
               
let x: number
  }
 
  return x;
        
let x: string | number
}

使用类型谓词

希望更直接地控制类型在整个代码中的变化方式
要定义用户定义的类型保护,我们只需要定义一个返回类型为类型谓词的函数
谓词采用 parameterName is Type 的形式,其中 parameterName 必须是当前函数签名中的参数名称

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

pet is Fish 是本例中的类型谓词
任何时候使用某个变量调用 isFish 时,如果基础类型兼容,TypeScript 就会将该变量缩小到该特定类型

// Both calls to 'swim' and 'fly' are now okay.
let pet = getSmallPet();
 
if (isFish(pet)) {
  pet.swim();
} else {
  pet.fly();
}
const zoo: (Fish | Bird)[] = [getSmallPet(), getSmallPet(), getSmallPet()];
const underWater1: Fish[] = zoo.filter(isFish);
// or, equivalently
const underWater2: Fish[] = zoo.filter(isFish) as Fish[];
 
// The predicate may need repeating for more complex examples
const underWater3: Fish[] = zoo.filter((pet): pet is Fish => {
  if (pet.name === "sharkey") return false;
  return isFish(pet);
});

断言函数

也可以使用 断言函数 缩小类型。


判别联合
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;
    //(parameter) shape: Circle
  }
}

同样的检查也适用于 switch 语句

function getArea(shape: Shape) {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
      //(parameter) shape: Circle
    case "square":
      return shape.sideLength ** 2;
      //(parameter) shape: Square
  }
}

never 类型

never 类型来表示不应该存在的状态。
缩小类型时,你可以将联合的选项减少到你已消除所有可能性并且一无所有的程度。在这些情况下,TypeScript 将使用 never 类型来表示不应该存在的状态。


穷举检查

never 类型可分配给每个类型;但是,没有类型可分配给 never(never 本身除外)

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;
  }
}

向 Shape 联合添加新成员,将导致 TypeScript 错误:

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;
     //Type 'Triangle' is not assignable to type 'never'.
      return _exhaustiveCheck;
  }
}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值