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;
  }
}
相关推荐
程序员的世界你不懂20 分钟前
(9)-Fiddler抓包-Fiddler如何设置捕获Https会话
前端·https·fiddler
MoFe125 分钟前
【.net core】天地图坐标转换为高德地图坐标(WGS84 坐标转 GCJ02 坐标)
java·前端·.netcore
去旅行、在路上1 小时前
chrome使用手机调试触屏web
前端·chrome
Aphasia3111 小时前
模式验证库——zod
前端·react.js
lexiangqicheng2 小时前
es6+和css3新增的特性有哪些
前端·es6·css3
拉不动的猪3 小时前
都25年啦,还有谁分不清双向绑定原理,响应式原理、v-model实现原理
前端·javascript·vue.js
烛阴3 小时前
Python枚举类Enum超详细入门与进阶全攻略
前端·python
孟孟~3 小时前
npm run dev 报错:Error: error:0308010C:digital envelope routines::unsupported
前端·npm·node.js
孟孟~3 小时前
npm install 报错:npm error: ...node_modules\deasync npm error command failed
前端·npm·node.js
狂炫一碗大米饭3 小时前
一文打通TypeScript 泛型
前端·javascript·typescript