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

如何将TypeScript多层索引器对象扁平化为键与属性结构?

如何将TypeScript多层索引器对象扁平化为键与属性结构?

嘿,我来帮你解决这个TypeScript对象扁平化的问题!先看看你给出的示例代码(看起来最后那段代码没写完,但核心结构我已经get到了):

const PluginFilterType = {
  boolean: 'boolean',
  string: 'string',
  date: 'date',
} as const;

const PluginFiltersMap = {
  project: {
    name: {
      type: PluginFilterType.string,
      label: 'Project Name',
    },
    framework: {
      type: PluginFilterType.date,
      label: 'Framework',
    },
  },
  service: {
    name: {
      type: PluginFilterType.string,
      label: 'Service Name',
    },
    // 这里应该还有其他属性,不过先按现有结构来处理
  },
};

你想要把这种嵌套的两层结构,扁平化成类似{ "project.name": { type: "...", label: "..." } }这样的键值对结构,对吧?我分两步来给你讲怎么实现,连TypeScript的类型提示都给你安排得明明白白。

第一步:定义扁平化后的类型

首先得搞定TypeScript的类型定义,这样扁平化后的对象能有正确的类型提示,不会写代码的时候一脸懵:

// 定义扁平化后的键类型,自动拼接成"group.key"的格式
type FlattenedFilterKeys<
  T extends Record<string, Record<string, any>>
> = `${keyof T & string}.${keyof T[keyof T] & string}`;

// 定义扁平化后的完整对象类型
type FlattenedFilters<
  T extends Record<string, Record<string, any>>
> = {
  [K in FlattenedFilterKeys<T>]: 
    K extends `${infer Group}.${infer Key}` 
      ? T[Group][Key] 
      : never;
};

这个类型会自动把外层键和内层键用点拼接起来,同时把对应的属性类型关联过去,后面写函数的时候TypeScript就会帮我们做类型检查啦。

第二步:实现扁平化函数

接下来就是写实际的扁平化函数,用两层循环就能轻松搞定,逻辑超清晰:

function flattenFilters<
  T extends Record<string, Record<string, any>>
>(filters: T): FlattenedFilters<T> {
  const result: Partial<FlattenedFilters<T>> = {};

  // 先遍历外层的分组,比如project、service
  for (const group in filters) {
    if (Object.prototype.hasOwnProperty.call(filters, group)) {
      const groupFilters = filters[group];
      // 再遍历每个分组里的具体筛选器
      for (const key in groupFilters) {
        if (Object.prototype.hasOwnProperty.call(groupFilters, key)) {
          const fullKey = `${group}.${key}` as FlattenedFilterKeys<T>;
          result[fullKey] = groupFilters[key];
        }
      }
    }
  }

  return result as FlattenedFilters<T>;
}

试试效果

现在直接调用这个函数,把你的PluginFiltersMap传进去就行:

const flattenedFilters = flattenFilters(PluginFiltersMap);

// 现在访问的时候TypeScript会有完整的类型提示哦
console.log(flattenedFilters['project.name'].label); // 输出 "Project Name"
console.log(flattenedFilters['service.name'].type); // 输出 "string"

如果你的对象以后有更多层级(比如三层甚至更深),可以把这个函数改成递归版本的,不过看你现在的需求是两层结构,这个实现完全够用啦。

备注:内容来源于stack exchange,提问作者Ori Pinhas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 16:25:29