You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中如何检查对象是否符合指定类型(含复合类型)?

在TypeScript中优雅区分两种数据类型的方案

要避免通过属性名硬判断,同时让TypeScript能正确做类型推断,核心思路是利用类型守卫(Type Guards)或判别式联合类型(Discriminated Unions),下面给你两种实用的方案:

方案一:用类型守卫区分基础类型与复合类型

如果你的「第一种类型」是值为基础类型(string/number/boolean)的对象,「第二种复合类型」是包含嵌套对象/数组的结构,可以按以下步骤实现:

1. 先定义类型

// 第一种:值全为基础类型的简单对象
type SimpleObject = Record<string, string | number | boolean>;

// 第二种:包含嵌套对象/数组的复合类型
type ComplexObject = Record<string, SimpleObject | ComplexObject | (SimpleObject | ComplexObject)[]>;

2. 编写类型守卫函数

类型守卫能在运行时判断类型,同时让TypeScript识别对应的类型:

// 判断值是否为基础类型
function isPrimitive(value: unknown): value is string | number | boolean {
  return ['string', 'number', 'boolean'].includes(typeof value);
}

// 判断对象是否为SimpleObject
function isSimpleObject(obj: unknown): obj is SimpleObject {
  if (typeof obj !== 'object' || obj === null) return false;
  // 验证所有属性值都是基础类型
  return Object.values(obj).every(isPrimitive);
}

// 判断对象是否为ComplexObject
function isComplexObject(obj: unknown): obj is ComplexObject {
  if (typeof obj !== 'object' || obj === null) return false;
  // 只要有一个属性值是复合结构即可判定
  return Object.values(obj).some(value => {
    if (Array.isArray(value)) {
      return value.some(item => isSimpleObject(item) || isComplexObject(item));
    }
    return isSimpleObject(value) || isComplexObject(value);
  });
}

3. 遍历并处理数据

借助类型守卫,遍历时代码会自动获得类型提示:

function handleData(data: SimpleObject | ComplexObject) {
  if (isSimpleObject(data)) {
    console.log('处理第一种简单类型对象:');
    for (const [key, value] of Object.entries(data)) {
      // TypeScript已推断value为基础类型,可直接安全处理
      console.log(`${key}: ${value}`);
    }
  } else {
    console.log('处理第二种复合类型对象:');
    for (const [key, value] of Object.entries(data)) {
      // 递归处理嵌套的复合结构
      if (Array.isArray(value)) {
        value.forEach(item => handleData(item));
      } else {
        handleData(value);
      }
    }
  }
}

方案二:用判别式联合类型(场景化最优解)

如果你的两种类型可以新增一个标识字段(比如type),这种方案会更简洁,TypeScript会自动帮你做类型窄化:

1. 定义带判别字段的联合类型

// 第一种类型:带type标识的简单对象
type SimpleItem = {
  type: 'simple';
  name: string;
  age: number;
  isActive: boolean;
};

// 第二种复合类型:带type标识的嵌套结构
type ComplexItem = {
  type: 'complex';
  children: (SimpleItem | ComplexItem)[];
  category: string;
};

// 联合类型
type DataItem = SimpleItem | ComplexItem;

2. 遍历并处理数据

直接通过type字段区分类型,无需额外守卫:

function processItem(item: DataItem) {
  for (const [key, value] of Object.entries(item)) {
    if (item.type === 'simple') {
      // TypeScript自动将item窄化为SimpleItem,所有属性值都是基础类型
      console.log(`简单属性 ${key}: ${value}`);
    } else {
      // TypeScript自动将item窄化为ComplexItem
      if (key === 'children') {
        // 递归处理子项数组
        (value as DataItem[]).forEach(processItem);
      } else {
        console.log(`复合属性 ${key}: ${value}`);
      }
    }
  }
}

为什么这两种方案更优雅?

  • 避免硬编码属性名的检查,属性名变更时只需修改类型定义,无需到处调整判断逻辑
  • TypeScript能正确推断类型,减少any类型的使用,提升代码安全性
  • 逻辑封装性好,类型判断逻辑集中在守卫函数或判别字段中,遍历代码更简洁

内容的提问来源于stack exchange,提问作者Mustafa Magdy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:59:47