TypeScript 类型保护与区分类型

类型保护与区分类型

在 TypeScript 中,类型保护是一种用于在运行时确定变量类型的机制,以便在特定的代码分支中进行更精确的类型操作。在处理联合类型或类型可能发生变化的情况下,确保代码的类型安全性和准确性。

从概念上讲,"区分类型"通常指的是在编程中明确地识别和处理不同的类型。

区分类型常常通过类型保护来实现。目的是为了在处理联合类型或可能具有多种类型的变量时,能够根据其实际的类型进行不同的操作。

typeof 类型保护

用于基本类型(如 numberstringbooleansymbol等)的判断。

typescript 复制代码
function processValue(value: number | string) {
  if (typeof value === "number") {
    // 这里 value 被确定为 number 类型
    console.log(value + 1);
  } else {
    // 这里 value 被确定为 string 类型
    console.log(value + "1");
  }
}

processValue(1); // 2
processValue("1"); // "11"

typeof类型保护 只有两种形式能被识别: typeof v === "typename"typeof v !== "typename"typename必须是 numberstringbooleansymbol

instanceof 类型保护

instanceof类型保护是通过构造函数来细化类型的一种方式。

用于类实例的类型判断:运行时确定一个对象是否是某个类的实例。

示例:

typescript 复制代码
class Animal {
  move() {
    console.log("The animal is moving.");
  }
}

class Dog extends Animal {
  run() {
    console.log("The dog is running!");
  }
}
class Cat extends Animal {
}

function doSomethingWithAnimal(animal: Animal) {
  if (animal instanceof Dog) {
    // 在这里,TypeScript 知道 animal 是 Dog 类型
    animal.run();
  } else {
    animal.move();
  }
}

let myDog = new Dog();
doSomethingWithAnimal(myDog); // The dog is running!

let myCat = new Cat();
doSomethingWithAnimal(myCat); // "The animal is moving."

在上述示例中,当 animal 被判断为 instanceof Dog 时,TypeScript 会将 animal 的类型细化为 Dog 类型,从而允许访问 Dog 类特有的方法。

instanceof的右侧要求是一个构造函数,TypeScript将细化为:

  1. 如果此构造函数的 prototype 属性的类型不是 any 类型,那么 TypeScript 会将其细化为该 prototype 属性的类型。
  2. 如果构造函数具有构造签名(即定义了如何创建实例的方式),那么会将构造签名所返回的类型也纳入考虑,形成一个联合类型。

instanceof 类型保护的原理是基于 JavaScript 中对象的原型链机制。只有当对象的原型链中包含了指定类的原型对象时,instanceof 才会返回 true

注意: instanceof 只适用于类创建的对象,对于普通的对象或者原始类型是不适用的。

in 操作符类型保护

用于检查对象是否具有特定的属性。

示例:

typescript 复制代码
interface Bird {
  fly(): void;
}

interface Fish {
  swim(): void;
}

function handleCreature(creature: Bird | Fish) {
  if ('fly' in creature) {
    // 这里 creature 被确定为 Bird 类型
    creature.fly();
  } else {
    // 这里 creature 被确定为 Fish 类型
    creature.swim();
  }
}

function getSmallPet1(): Fish | Bird {
  return {
    fly: () => console.log("fly")
  }
}

function getSmallPet2(): Fish | Bird {
  return {
    swim: () => console.log("swim")
  }
}
let pet1 = getSmallPet1();
handleCreature(pet1); // fly

let pet2 = getSmallPet2();
handleCreature(pet2); // swim

用户自定义的类型保护

用户自定义的类型保护函数是通过返回一个类型谓词来实现的。类型谓词的形式是 parameterName is Type ,其中 parameterName 是要检查的参数名称, Type 是要断言的类型。

把上面的示例改成自定义的类型保护:

typescript 复制代码
function isBird(creature: Bird | Fish): creature is Bird {
  return (creature as Bird).fly!== undefined;
}

function handleCreature(creature: Bird | Fish) {
  if (isBird(creature)) {
    creature.fly();
  } else {
    creature.swim();
  }
}

isBird 函数就是一个用户自定义的类型保护函数。它根据对象是否具有 fly 方法来判断传入的对象是否为 Bird 类型。
creature is Bird就是类型谓词。

每当使用一些变量调用 isBird 时,TypeScript会将变量缩减为那个具体的类型,只要这个类型与变量的原始类型是兼容的。

相关推荐
www_stdio6 分钟前
JavaScript 执行机制详解:从 V8 引擎到执行上下文
前端·javascript
我命由我1234518 分钟前
HTML - 换行标签的 3 种写法(<br>、<br/>、<br />)
前端·javascript·css·html·css3·html5·js
icebreaker1 小时前
重新思考 weapp-tailwindcss 的未来
前端·javascript·css
涤生啊1 小时前
一键搭建 Coze 智能体对话页面:支持流式输出 + 图片直显,开发效率拉满!
javascript·html5
吃饺子不吃馅2 小时前
⚡️ Zustand 撤销重做利器:Zundo 实现原理深度解析
前端·javascript·github
NON-JUDGMENTAL2 小时前
在 Ubuntu 上安装 Ollama 并通过 Open WebUI 运行本地大语言模型
linux·ubuntu·语言模型
小白也想学C2 小时前
ubuntu22.04下载QQ音乐闪退问题
ubuntu
海蓝可知天湛3 小时前
Ubuntu24.10禁用该源...+vmware无法复制黏贴“天坑闭环”——从 DNS 诡异解析到 Ubuntu EOL 引发的 apt 404排除折
linux·ubuntu
远航_3 小时前
10 个被严重低估的 JS 特性,直接少写 500 行代码
前端·javascript
小高0073 小时前
当前端面临百万级 API 请求:从"修 CSS 的"到架构师的进化之路
前端·javascript·面试