TypeScript 类型判断方法详解与比较

在 TypeScript 中,我们常常需要判断一个对象属于某种类型。以下是几种常见的类型判断方式:


1. instanceof 操作符

原理:

判断对象是否是某个构造函数(类)创建的实例。

ts 复制代码
class Dog {
  bark() {}
}
const d = new Dog();

console.log(d instanceof Dog); // true

优点:

  • 简洁直观。
  • 适用于类(class)实例判断。

缺点:

  • 只能用于类,不适用于接口(interface)。
  • 无法跨 iframe 或跨 window 使用。
  • 在前端库中用得较少,因为很多类型是接口而不是类。

2. 判别联合类型(Discriminated Union)

原理:

使用一个 字面量类型属性(通常叫 kind/type/tag) 来区分联合类型。

ts 复制代码
type Circle = { kind: 'circle'; radius: number };
type Square = { kind: 'square'; side: number };
type Shape = Circle | Square;

function getArea(shape: Shape): number {
  if (shape.kind === 'circle') {
    return Math.PI * shape.radius ** 2;
  } else {
    return shape.side ** 2;
  }
}

优点:

  • 简洁、类型安全。
  • IDE 自动提示好。
  • 编译器能进行详尽的类型缩小和检查(如 switch 的穷尽检查)。

缺点:

  • 依赖于人为维护 kind 字段,一旦忘记添加或拼写错误,就会出错。
  • 不适用于运行时动态类型的判断。

3. 自定义类型保护函数(Type Predicate)

原理:

编写返回布尔值的函数,配合返回值类型谓词来帮助 TypeScript 缩小类型。

ts 复制代码
type Cat = { meow: () => void };
type Dog = { bark: () => void };

function isCat(pet: Cat | Dog): pet is Cat {
  return (pet as Cat).meow !== undefined;
}

优点:

  • 类型缩小灵活,支持复杂逻辑判断。
  • 可复用、单元测试友好。

缺点:

  • 需要手动书写,较繁琐。
  • 如果判断逻辑不准确可能造成错误类型推断。

4. typeof 操作符

原理:

判断原始类型(number, string, boolean, symbol, bigint, undefined, function)。

ts 复制代码
function doSomething(x: number | string) {
  if (typeof x === "string") {
    console.log(x.toUpperCase());
  }
}

优点:

  • 语法简单。
  • 编译器原生支持。

缺点:

  • 只能用于原始类型,无法用于对象类型或自定义类型。

5. 属性存在性检查(in 操作符)

原理:

通过判断某属性是否在对象中来缩小类型。

ts 复制代码
type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}

优点:

  • 简单,适合对象类型判断。
  • 无需定义额外的字段。

缺点:

  • 属性名可能冲突或变动,带来维护成本。
  • 不能完全替代类型标识字段。

6. 结构判断(Duck Typing)

原理:

依赖对象结构自动推断类型。

ts 复制代码
function greet(obj: { name: string }) {
  console.log(obj.name);
}

优点:

  • 灵活,无需显式定义类型。

缺点:

  • 容易造成类型混淆。
  • 难以进行运行时安全判断。

比较总结

方法 可判断范围 运行时可用 类型安全 简洁性 适用场景
instanceof 类实例 判断类(class)实例
判别联合类型(Discriminated Union) 联合类型(需标记字段) ✅✅ 类型定义中区分类别
类型保护函数 任意类型 ✅✅ 通用复杂类型判断
typeof 原始类型 字符串、数字、布尔等基础类型
in 操作符 对象结构判断 判断某字段是否存在
结构判断(Duck Typing) 任意结构 临时快速判断,不推荐严谨使用

最佳实践建议

  1. 首选:判别联合类型

    • 用于类型系统设计中的联合类型判断。
    • 优雅且类型安全,支持 IDE 推断。
  2. 类对象:使用 instanceof

    • 判断是否为某个类的实例。
  3. 复杂判断逻辑:自定义类型保护函数

    • 用于多字段综合判断。
    • 建议封装成独立函数,便于测试和复用。
  4. 原始类型:使用 typeof

    • 简单有效。
  5. 对象字段存在性判断:使用 in

    • 适合有明显结构区分的类型。

示例:综合使用示意

ts 复制代码
type Cat = { kind: 'cat'; meow: () => void };
type Dog = { kind: 'dog'; bark: () => void };
type Animal = Cat | Dog;

function handleAnimal(animal: Animal) {
  switch (animal.kind) {
    case 'cat':
      animal.meow();
      break;
    case 'dog':
      animal.bark();
      break;
  }
}
相关推荐
GISer_Jing2 小时前
前端面试通关:Cesium+Three+React优化+TypeScript实战+ECharts性能方案
前端·react.js·面试
落霞的思绪3 小时前
CSS复习
前端·css
咖啡の猫5 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲7 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5818 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路8 小时前
GeoTools 读取影像元数据
前端
ssshooter9 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
Jerry9 小时前
Jetpack Compose 中的状态
前端
dae bal10 小时前
关于RSA和AES加密
前端·vue.js
柳杉10 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化