在 TypeScript 中,类型缩小和类型保护是非常重要的概念,它们可以帮助我们在代码中更精确地定义和使用类型,从而避免一些常见的错误和 bug。本文将详细介绍 TypeScript 中的类型缩小和类型保护,包括它们的定义、使用方法和示例代码,希望对前端开发者有所帮助。
什么是类型缩小?
类型缩小指的是在 TypeScript 中根据某些条件缩小变量的类型范围,使得变量的类型更加精确。简单来说,就是根据变量的值或其他条件,推断出变量的具体类型。
类型缩小的方式
在 TypeScript 中,有多种方式可以进行类型缩小,包括以下几种:
typeof 操作符
typeof 操作符可以用来获取一个变量的类型,例如:
const x = 10; const y = "hello"; console.log(typeof x); // 输出 "number" console.log(typeof y); // 输出 "string"
当我们使用 typeof 操作符对一个变量进行类型判断时,TypeScript 会自动缩小这个变量的类型范围,例如:
function printValue(value: number | string) {
if (typeof value === "number") {
console.log(value.toFixed(2)); // 只有当 value 的类型为 number 时才能调用 toFixed 方法
} else {
console.log(value.toUpperCase()); // 只有当 value 的类型为 string 时才能调用 toUpperCase 方法
}
}在上面的代码中,我们使用 typeof 操作符缩小了 value 变量的类型范围,使得我们可以根据变量的值来调用不同的方法。
instanceof 操作符
instanceof 操作符可以用来判断一个对象是否属于某个类,例如:
class Animal {}
class Dog extends Animal {}
const animal = new Animal();
const dog = new Dog();
console.log(animal instanceof Animal); // 输出 true
console.log(dog instanceof Dog); // 输出 true
console.log(dog instanceof Animal); // 输出 true,因为 Dog 继承自 Animal当我们使用 instanceof 操作符对一个对象进行类型判断时,TypeScript 会自动缩小这个对象的类型范围,例如:
function printSound(animal: Animal | Dog) {
if (animal instanceof Dog) {
console.log("汪汪汪"); // 只有当 animal 的类型为 Dog 时才能输出汪汪汪
} else {
console.log("咩咩咩"); // 只有当 animal 的类型为 Animal 时才能输出咩咩咩
}
}在上面的代码中,我们使用 instanceof 操作符缩小了 animal 对象的类型范围,使得我们可以根据对象的类型来输出不同的声音。
in 操作符
in 操作符可以用来判断一个对象是否包含某个属性,例如:
// www.javascriptcn.com code example
interface Person {
name: string;
age: number;
}
const person: Person = {
name: "张三",
age: 20,
};
console.log("name" in person); // 输出 true
console.log("gender" in person); // 输出 false当我们使用 in 操作符对一个对象进行类型判断时,TypeScript 会自动缩小这个对象的类型范围,例如:
function printNameOrAge(person: Person | { name: string } | { age: number }) {
if ("name" in person) {
console.log(person.name); // 只有当 person 包含 name 属性时才能输出 name
} else {
console.log(person.age); // 只有当 person 包含 age 属性时才能输出 age
}
}在上面的代码中,我们使用 in 操作符缩小了 person 对象的类型范围,使得我们可以根据对象的属性来输出不同的信息。
自定义类型保护函数
除了上面的几种方式外,我们还可以通过自定义类型保护函数来进行类型缩小。类型保护函数是一个返回值为布尔类型的函数,它的参数是一个变量,用于判断这个变量是否属于某个特定的类型。例如:
// www.javascriptcn.com code example
interface Fish {
swim(): void;
}
interface Bird {
fly(): void;
}
function isFish(animal: Fish | Bird): animal is Fish {
return typeof (animal as Fish).swim === "function";
}在上面的代码中,我们定义了一个 isFish 函数,用于判断 animal 变量是否属于 Fish 类型。如果 animal 变量的 swim 方法存在,则说明它属于 Fish 类型,返回 true,否则返回 false。在使用 isFish 函数时,需要使用 animal is Fish 这种语法来指定返回值类型,例如:
function printSwimOrFly(animal: Fish | Bird) {
if (isFish(animal)) {
animal.swim(); // 只有当 animal 的类型为 Fish 时才能调用 swim 方法
} else {
animal.fly(); // 只有当 animal 的类型为 Bird 时才能调用 fly 方法
}
}在上面的代码中,我们使用自定义的 isFish 函数缩小了 animal 变量的类型范围,使得我们可以根据变量的类型来调用不同的方法。
类型缩小的注意事项
在使用类型缩小时,需要注意以下几点:
- 缩小类型范围后,变量的类型不会发生改变,仍然是原来的类型,只是类型范围更加精确。
- 缩小类型范围后,不能对变量进行赋值操作,因为 TypeScript 无法确定变量的具体类型。
- 缩小类型范围后,如果使用了不存在的属性或方法,会导致编译错误。
什么是类型保护?
类型保护指的是在 TypeScript 中通过某些方式判断一个变量的类型,从而使得变量在特定的代码块中具有特定的类型。简单来说,就是根据变量的类型来确定变量的具体类型。
类型保护的方式
在 TypeScript 中,有多种方式可以进行类型保护,包括以下几种:
类型断言
类型断言可以用来将一个变量强制转换成某个类型,例如:
const x: unknown = "hello"; const y = (x as string).toUpperCase(); // 将 x 转换成 string 类型 console.log(y); // 输出 "HELLO"
当我们使用类型断言对一个变量进行类型判断时,TypeScript 会自动推断出变量的具体类型,例如:
// www.javascriptcn.com code example
function printValue(value: number | string) {
if (typeof value === "number") {
const x = value as number; // 将 value 转换成 number 类型
console.log(x.toFixed(2)); // 只有当 value 的类型为 number 时才能调用 toFixed 方法
} else {
const y = value as string; // 将 value 转换成 string 类型
console.log(y.toUpperCase()); // 只有当 value 的类型为 string 时才能调用 toUpperCase 方法
}
}在上面的代码中,我们使用类型断言对 value 变量进行了类型判断,使得我们可以根据变量的类型来调用不同的方法。
instanceof 操作符
在类型缩小中已经介绍了 instanceof 操作符,它也可以用来进行类型保护,例如:
// www.javascriptcn.com code example
class Animal {}
class Dog extends Animal {}
function printSound(animal: Animal | Dog) {
if (animal instanceof Dog) {
const dog = animal as Dog; // 将 animal 转换成 Dog 类型
console.log(dog.bark()); // 只有当 animal 的类型为 Dog 时才能调用 bark 方法
} else {
const animal = animal as Animal; // 将 animal 转换成 Animal 类型
console.log(animal.makeSound()); // 只有当 animal 的类型为 Animal 时才能调用 makeSound 方法
}
}在上面的代码中,我们使用 instanceof 操作符对 animal 变量进行了类型判断,使得我们可以根据变量的类型来调用不同的方法。
自定义类型保护函数
在类型缩小中已经介绍了自定义类型保护函数,它也可以用来进行类型保护,例如:
// www.javascriptcn.com code example
interface Fish {
swim(): void;
}
interface Bird {
fly(): void;
}
function isFish(animal: Fish | Bird): animal is Fish {
return typeof (animal as Fish).swim === "function";
}
function printSwimOrFly(animal: Fish | Bird) {
if (isFish(animal)) {
const fish = animal as Fish; // 将 animal 转换成 Fish 类型
fish.swim(); // 只有当 animal 的类型为 Fish 时才能调用 swim 方法
} else {
const bird = animal as Bird; // 将 animal 转换成 Bird 类型
bird.fly(); // 只有当 animal 的类型为 Bird 时才能调用 fly 方法
}
}在上面的代码中,我们使用自定义的 isFish 函数对 animal 变量进行了类型判断,使得我们可以根据变量的类型来调用不同的方法。
类型保护的注意事项
在使用类型保护时,需要注意以下几点:
- 类型保护只在特定的代码块中有效,离开这个代码块后变量的类型会恢复成原来的类型。
- 类型保护只能对变量的类型进行缩小,不能对变量的类型进行扩大。
- 类型保护的范围不能太大,否则会影响代码的可读性和可维护性。
示例代码
下面是一个使用类型缩小和类型保护的示例代码,用于判断一个变量是不是数组或对象:
// www.javascriptcn.com code example
function printArrayOrObject(value: unknown) {
if (Array.isArray(value)) {
const arr = value as unknown[]; // 将 value 转换成 unknown[] 类型
console.log(arr.join(",")); // 只有当 value 的类型为数组时才能调用 join 方法
} else if (typeof value === "object" && value !== null) {
const obj = value as Record<string, unknown>; // 将 value 转换成 Record<string, unknown> 类型
console.log(Object.keys(obj).join(",")); // 只有当 value 的类型为对象时才能调用 Object.keys 方法
} else {
console.log("不是数组或对象");
}
}
printArrayOrObject([1, 2, 3]); // 输出 "1,2,3"
printArrayOrObject({ name: "张三", age: 20 }); // 输出 "name,age"
printArrayOrObject("hello"); // 输出 "不是数组或对象"在上面的代码中,我们使用了 typeof、Array.isArray 和自定义类型保护函数 isObject 来对 value 变量进行了类型缩小和类型保护,使得我们可以根据变量的类型来调用不同的方法。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d2b19da941bf713453e041