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;
  }
}
相关推荐
cc.ChenLy3 分钟前
浏览器缓存机制详解:如何彻底解决前端代码更新后的缓存问题
前端
XTTX1109 分钟前
Vue3+Cesium电子围栏效果
前端·javascript·vue.js
KevinWang_28 分钟前
AI 基础设施及其应用
前端
AIFarmer29 分钟前
npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确, 然后再试一次。
前端·npm·node.js
小红的布丁33 分钟前
Redis 集群详解:主从哨兵和切片集群有什么区别
前端·数据库·redis
小高0071 小时前
🔥前端性能内卷终点?Signals 正在重塑我们的开发习惯
前端·javascript·vue.js
周末也要写八哥1 小时前
HTML网页设计入门之“做前端”的基本思路
前端·html
VelinX1 小时前
【个人学习||vue】
前端·vue.js·学习
禅思院1 小时前
前端性能优化:从“术“到“道“的完整修炼指南
前端·性能优化·前端性能优化·分层优化模
用泥种荷花1 小时前
OpenClaw 插件开发避坑指南
前端