chengaofeng
发布于 2024-07-16 / 14 阅读
0
0

Typescript类型守卫、类型转换、自定义守卫

类型断言

let a: A
let b: B = a as B
  1. 绕过TS编译检查,类型断言就是告诉编译器我是这个类型,无需检查

  2. 类型必须有重合才能断言

  3. 类型断言应用场景:

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  move(distance: number = 0) {
    console.log(`${this.name} moved ${distance}m.`);
  }
}

class Dog extends Animal {
  type: string = "dog";
  age: number;
  constructor(name: string, age: number) {
    super(name);
    this.age = age;
  }
  bark() {
    console.log("Woof! Woof!");
  }
}

class Cat extends Animal {
  type: string = "cat";
  age: number;
  constructor(name: string, age: number) {
    super(name);
    this.age = age;
  }
  meow() {
    console.log("Meow! Meow!");
  }
}

class People {
  hasPet(animal: Animal) {
    console.log(`I have a ${animal.name}`);
    // 如果想调用子类的方法,就需要使用类型断言
    let cat = animal as Cat;
    cat.meow();
  }
}

let p = new People();
let cat = new Cat("Kitty", 2);
p.hasPet(cat);
// I have a Kitty
// Meow! Meow!

export {};

类型转换

编译器强制一个类型转换成另外一个类型

let a = new Animal("Animal");
let dog = <Dog>a; // 强制类型转换,不会报错,但是运行时会报错
dog.bark(); // 报错 TypeError: dog.bark is not a function  动物中没有bark方法
let dog1 = new Dog("Dog", 3);
let a1 = <Animal>dog1 // 强制类型转换,不会报错,子类转父类不会报错
a1.move(10); // Dog moved 10m.

类型守卫

typeof局限性和替代方案

  1. 作用:用来检测一个变量或一个对象的数据类型

  2. 检测的范围:”string“ | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"等数据类型

  3. 局限性:无法检查数组、Set、Map的具体类型,返回都是object

const arr = ['a', 'b', 'c'];
const set = new Set(arr);
const map = new Map();
console.log(typeof arr); // object
console.log(typeof set); // object
console.log(typeof map); // object
  1. 替代方案1: 有缺陷,无法判断实例的准确类型

const arr = ["a", "b", "c"];
const set = new Set(arr);
const map = new Map();
console.log(typeof arr); // object
console.log(typeof set); // object
console.log(typeof map); // object
// 使用Object.prototype.toString.call()方法可以准确判断数据类型
console.log(Object.prototype.toString.call(arr)); // [object Array]
console.log(Object.prototype.toString.call(set)); // [object Set]
console.log(Object.prototype.toString.call(map)); // [object Map]
// 无法判断实例的具体类型,只能判断是否为对象
let p1 = new People();
console.log(Object.prototype.toString.call(p1)); // [object Object]
  1. 替代方案2:类型守卫

什么是类型守卫?

在语句的块级作用域【if语句内或三目运算符表达式内】缩小变量的一种类型推断的行为

类型守卫产生时机?

TS条件语句中遇到下列条件关键字时,会在语句的块级作用域内缩小变量的类型,这种类型推断的行为称作类型守卫。类型守卫可以帮助我们在块级作用域中获得更为需要的精确变量类型。

  1. 实例判断:instanceof

  2. 属性或者方法判断:in

  3. 类型判断:typeof

  4. 字面量相等判断:=====!=!==

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  move(distance: number = 0) {
    console.log(`${this.name} moved ${distance}m.`);
  }
}

class Dog extends Animal {
  type: string = "dog";
  age: number;
  constructor(name: string, age: number) {
    super(name);
    this.age = age;
  }
  bark() {
    console.log("Woof! Woof!");
  }
}

class Cat extends Animal {
  type: string = "cat";
  age: number;
  constructor(name: string, age: number) {
    super(name);
    this.age = age;
  }
  meow() {
    console.log("Meow! Meow!");
  }
}

class People {
  hasPet(animal: Dog | Cat) {
    console.log(`I have a ${animal.name}`);
    // 类型守卫 instanceof
    if (animal instanceof Dog) {
      animal.bark();
    } else {
      animal.meow();
    }
    // 类型守卫 in
    if ("bark" in animal) {
      animal.bark();
    } else {
      animal.meow();
    }
  }
}

let dog = new Dog("dog", 2);
let cat = new Cat("cat", 1);
let people = new People();
people.hasPet(dog); // I have a dog
people.hasPet(cat); // I have a cat
// I have a dog
// Woof! Woof!
// I have a cat
// Meow! Meow!

export {};

自定义守卫

当某些类型判断使用类型守卫较多时,可以封装成自定义守卫

// 语法
function 函数名(形参: 参数类型【参数类型大多为any】): 形参 is A类型 {
  return true or false;
}

function isDog(animal: Dog | Cat): animal is Dog {
  return (animal as Dog).bark !== undefined;
}

function isCat(animal: Dog | Cat): animal is Cat {
  return animal instanceof Cat;
}

class People {
  hasPet(animal: Dog | Cat) {
    // 自定义类型守卫
    if (isDog(animal)) {
      animal.bark();
    } else {
      animal.meow();
    }
  }
}

Vue3源码中的自定义守卫

export function isRef(r: any): r is Ref {
  return Boolean(r && r.__v_isRef === true);
}


评论