翼度科技»论坛 编程开发 JavaScript 查看内容

JavaScript断言与类型守卫及联合声明超详细介绍

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
一、TypeScript 断言


1.1 类型断言

个人理解的断言,就是断定某一个值的类型,此时TypeScript以你所给出的值类型为准,而非TypeScrip的推论
在一些复杂的类型声明 变成具体实现时往往用得到 并且避免很多类型过于复杂的情况
类型断言有两种形式:

1.尖括号语法
  1. const someValue: any = "this is a string";
  2. let strLength: number = (<{a:number}>someValue).a;
复制代码
2.as 语法

这个用的比较多
  1. let someValue = "this is a string" as string;
  2. let strLength: number = someValue.length;
复制代码
1.2 非空断言

TypeScript 提供了一个特殊的语法,可以在不做任何检查的情况下,从类型中移除 null 和 undefined,这就是在任意表达式后面写上 ! ,这是一个有效的类型断言,表示它的值不可能是 null 或者 undefined:

1.3 确定赋值断言

在 TypeScript 2.7 版本中引入了确定赋值断言,即允许在实例属性和变量声明后面放置一个
  1. !
复制代码
号,从而告诉 TypeScript 该属性会被明确地赋值。为了更好地理解它的作用,我们来看个具体的例子:
  1. let x: number;
  2. console.log(2 * x);
复制代码
很明显会有报错,因为在赋值前使用变量,要解决该问题,我们可以使用确定赋值断言:
  1. let x!: number;
  2. console.log(2 * x);  
复制代码
二、类型守卫

类型保护是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内。 换句话说,类型保护可以保证一个字符串是一个字符串,尽管它的值也可以是一个数值。
  1. //
  2. function add(padding: number | string) {
  3.   return padding + 10;  //运算符“+”不能应用于类型“string | number”和“number”。
  4. }
复制代码
类型保护与特性检测并不是完全不同,其主要思想是尝试检测属性、方法或原型,以确定如何处理值。目前主要有四种的方式来实现类型保护:

2.1 in关键字

js中的in 关键字 如果指定的属性在指定的对象或其原型链中,则 in 运算符返回 true。
  1. const car = { make: 'Honda', model: 'Accord', year: 1998 };
  2. console.log('make' in car);  //true
  3. delete car.make;
  4. if ('make' in car === false) {
  5.   car.make = 'Suzuki';
  6. }
  7. console.log(car.make); //Suzuki
复制代码
typescript也是类似的
  1. interface Admin {
  2.   name: string;
  3.   privileges: string[];
  4. }
  5. interface Employee {
  6.   name: string;
  7.   startDate: Date;
  8. }
  9. type UnknownEmployee = Employee | Admin;
  10. function printEmployeeInformation(emp: UnknownEmployee) {
  11.   console.log("Name: " + emp.name);
  12.   if ("privileges" in emp) {
  13.     console.log("Privileges: " + emp.privileges);
  14.   }
  15.   if ("startDate" in emp) {
  16.     console.log("Start Date: " + emp.startDate);
  17.   }
  18. }
复制代码
2.2 typeof关键字
  1. // “number”, “string”, “boolean” , “symbol”
复制代码
  1. function padLeft(value: string, padding: string | number) {
  2.   if (typeof padding === "number") {
  3.       return Array(padding + 1).join(" ") + value;
  4.   }
  5.   if (typeof padding === "string") {
  6.       return padding + value;
  7.   }
  8.   throw new Error(`Expected string or number, got '${padding}'.`);
  9. }
复制代码
  1. typeof
复制代码
类型保护只支持两种形式:
  1. typeof v === "typename"
复制代码
  1. typeof v !== typename
复制代码
  1. "typename"
复制代码
必须是
  1. "number"
复制代码
  1. "string"
复制代码
  1. "boolean"
复制代码
  1. "symbol"
复制代码
。 但是 TypeScript 并不会阻止你与其它字符串比较,语言不会把那些表达式识别为类型保护。

2.3 instanceof 关键字

当联合类型中使用的是 class 而不是 interface 时,instanceof 语法就派上用场了,通过 instanceof 语法可以区分不同的 class 类型。
  1. class Bird {
  2.   // 独有方法
  3.   fly() {};
  4.   // 共有方法
  5.   layEggs() {};
  6. }
  7. class Fish {
  8.   // 独有方法
  9.   swim() {};
  10.   // 共有方法
  11.   layEggs() {};
  12. }
  13. function getSmallPet(): Fish | Bird {
  14.   // ...
  15. }
  16. let pet = getSmallPet();
  17. pet.layEggs(); // 正常
  18. // 使用 in 语法进行
  19. if (pet instanceof Bird) {
  20.   pet.fly()
  21. } else {
  22.   pet.swim()
  23. }
复制代码
2.4 **自定义类型保护的类型谓词
  1. function isNumber(x: any): x is number {
  2.   return typeof x === "number";
  3. }
  4. function isString(x: any): x is string {
  5.   return typeof x === "string";
  6. }
  7. function isFish(pet: Fish | Bird): pet is Fish {
  8.     return (<Fish>pet).swim !== undefined;
  9. }
  10. if (pagination.pageSize != _pagination.pageSize && (<ListObjProps<T, K>>listProps).pagination?.pageSize) {
  11.       localStorage.setItem(FeManagePageSize, _pagination.pageSize?.toString() || '10')
  12.   }
复制代码


三、联合类型和类型别名


3.1 联合类型

联合类型通常与
  1. null
复制代码
  1. undefined
复制代码
一起使用:
  1. const abc = (name: string | undefined) => {
  2. };
复制代码
例如,这里
  1. name
复制代码
的类型是
  1. string | undefined
复制代码
意味着可以将
  1. string
复制代码
  1. undefined
复制代码
的值传递给
  1. abc
复制代码
函数。
  1. abc("semlinker");
  2. abc(undefined);
复制代码
通过这个示例,你可以凭直觉知道类型 A 和类型 B 联合后的类型是同时接受 A 和 B 值的类型。此外,对于联合类型来说,你可能会遇到以下的用法:
  1. let num: 1 | 2 = 1;
  2. type Type = 'click' | 'doubleClick' | 'mousemove';
复制代码
3.2 可辨识联合

TypeScript 可辨识联合(Discriminated Unions)类型,也称为代数数据类型或标签联合类型。它包含 3 个要点:可辨识、联合类型和类型守卫。
这种类型的本质是结合联合类型和字面量类型的一种类型保护方法。如果一个类型是多个类型的联合类型,且多个类型含有一个公共属性,那么就可以利用这个公共属性,来创建不同的类型保护区块。

1. 可辨识

可辨识要求联合类型中的每个元素都含有一个单例类型属性,比如:
  1. enum CarTransmission {
  2.   Automatic = 200,
  3.   Manual = 300
  4. }
  5. interface Motorcycle {
  6.   vType: "motorcycle";
  7.   make: number;
  8. }
  9. interface Car {
  10.   vType: "car";
  11.   transmission: CarTransmission
  12. }
  13. interface Truck {
  14.   vType: "truck";
  15.   capacity: number;
  16. }
复制代码
在上述代码中,我们分别定义了
  1. Motorcycle
复制代码
  1. Car
复制代码
  1. Truck
复制代码
三个接口,在这些接口中都包含一个
  1. vType
复制代码
属性,该属性被称为可辨识的属性,而其它的属性只跟特性的接口相关。

2. 联合类型

基于前面定义了三个接口,我们可以创建一个
  1. Vehicle
复制代码
联合类型:
  1. type Vehicle = Motorcycle | Car | Truck;
复制代码
现在我们就可以开始使用
  1. Vehicle
复制代码
联合类型,对于
  1. Vehicle
复制代码
类型的变量,它可以表示不同类型的车辆。

3. 类型守卫

下面我们来定义一个
  1. evaluatePrice
复制代码
方法,该方法用于根据车辆的类型、容量和评估因子来计算价格,具体实现如下:
  1. const EVALUATION_FACTOR = Math.PI;
  2. function evaluatePrice(vehicle: Vehicle) {
  3.   return vehicle.capacity * EVALUATION_FACTOR;
  4. }
  5. const myTruck: Truck = { vType: "truck", capacity: 9.5 };
  6. evaluatePrice(myTruck);
复制代码

原因是在 Motorcycle 接口中,并不存在
  1. capacity
复制代码
属性,而对于 Car 接口来说,它也不存在
  1. capacity
复制代码
属性。那么,现在我们应该如何解决以上问题呢?这时,我们可以使用类型守卫。下面我们来重构一下前面定义的
  1. evaluatePrice
复制代码
方法,重构后的代码如下:
  1. function evaluatePrice(vehicle: Vehicle) {
  2.   switch(vehicle.vType) {
  3.     case "car":
  4.       return vehicle.transmission * EVALUATION_FACTOR;
  5.     case "truck":
  6.       return vehicle.capacity * EVALUATION_FACTOR;
  7.     case "motorcycle":
  8.       return vehicle.make * EVALUATION_FACTOR;
  9.   }
  10. }
复制代码
在以上代码中,我们使用
  1. switch
复制代码
  1. case
复制代码
运算符来实现类型守卫,从而确保在
  1. evaluatePrice
复制代码
方法中,我们可以安全地访问
  1. vehicle
复制代码
对象中的所包含的属性,来正确的计算该车辆类型所对应的价格。

3.3 类型别名

类型别名用来给一个类型起个新名字。
  1. type Message = string | string[];
  2. let greet = (message: Message) => {
  3. };
  4. ACTOR;
  5.   }
  6. }
复制代码
在以上代码中,我们使用
  1. switch
复制代码
  1. case
复制代码
运算符来实现类型守卫,从而确保在
  1. evaluatePrice
复制代码
方法中,我们可以安全地访问
  1. vehicle
复制代码
对象中的所包含的属性,来正确的计算该车辆类型所对应的价格。
到此这篇关于JavaScript断言与类型守卫及联合声明超详细介绍的文章就介绍到这了,更多相关JS断言与类型守卫及联合声明内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

来源:https://www.jb51.net/article/266677.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具