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;
  }
}
相关推荐
arvin_xiaoting2 小时前
OpenClaw学习总结_I_核心架构_8:SessionPruning详解
前端·chrome·学习·系统架构·ai agent·openclaw·sessionpruning
工程师老罗3 小时前
Image(图像)的用法
java·前端·javascript
swipe4 小时前
把 JavaScript 原型讲透:从 `[[Prototype]]`、`prototype` 到 `constructor` 的完整心智模型
前端·javascript·面试
问道飞鱼4 小时前
【前端知识】React 组件生命周期:从底层原理到实践场景
前端·react.js·前端框架·生命周期
CHU7290354 小时前
定制专属美丽时刻:美容预约商城小程序的贴心设计
前端·小程序
浩~~5 小时前
反射型XSS注入
前端·xss
AwesomeDevin5 小时前
AI时代,我们的任务不应沉溺于与 AI 聊天,🤔 从“对话式编程”迈向“数字软件工厂”
前端·后端·架构
harrain5 小时前
antvG2折线图和区间range标记同时绘制
前端·javascript·vue.js·antv·g2
德育处主任Pro5 小时前
从重复搭建到高效生产,RollCode的H5开发新范式
前端
蜡台5 小时前
SPA(Single Page Application) Web 应用(即单页应用)架构模式 更新
前端·架构·vue·react·spa·spa更新