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;
  }
}
相关推荐
用户461169657285 分钟前
网站 HTTPS 不稳定?证书排查指南
前端
n876517 分钟前
Playwright Java WEB UI 自动化实现框架与逻辑
java·前端·ui
keyipatience18 分钟前
TypeScript学习(1)
前端·javascript·学习·typescript·html·css3
xifangge20251 小时前
基于 JavaScript 实现 CNC 数控切削参数与螺纹公差纯前端核算引擎
开发语言·前端·javascript
wangruofeng1 小时前
2026 Web 技术选型指南,AI 时代如何选择适合项目的技术栈
前端·aigc·ai编程
honkun61 小时前
vue 表格组件 vxe-table 修改滚动条样式,修改滚动条样式,统一宽度、颜色与自动隐藏
前端·javascript·vue.js
爱勇宝2 小时前
研究数字孪生的这半年,做了个 Demo,也有了一些新想法
前端·程序员
不可能片场2 小时前
工程实践 一个缓存把选片从十分钟压到一分钟
前端·electron
前端小万2 小时前
探索副业五个月,最终以放弃告终
前端·后端·面试
FRing032 小时前
JavaScript入门到精通二十四(正则表达式、元字符、修饰符)
开发语言·前端·javascript·正则表达式