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

如何深度扁平化带联合类型的TypeScript接口并在键中保留完整对象路径

TypeScript 嵌套接口扁平化实现

完整类型定义

// 辅助类型:判断对象属性是否为可选属性
type IsOptional<T, K extends keyof T> = {} extends Pick<T, K> ? true : false;

// 辅助类型:合并交叉类型为单个对象,优化类型显示效果
type Merge<T> = { [K in keyof T]: T[K] } extends infer O ? O : never;

// 辅助类型:处理单个类型的扁平化逻辑
type FlattenSingle<T, Path extends string = never> = 
  // 非对象类型(原始类型、函数等)直接返回路径为键的对象
  T extends object ? 
    // 遍历对象所有属性
    { [K in keyof T]-?: 
      // 拼接当前属性的完整路径
      (IsOptional<T, K> extends true ? 
        // 可选属性生成带可选标记的扁平化结果
        Partial<FlattenSingle<T[K], Path extends never ? `${K & string}` : `${Path}.${K & string}`>>
        : 
        // 必选属性直接生成扁平化结果
        FlattenSingle<T[K], Path extends never ? `${K & string}` : `${Path}.${K & string}`>
      )
    // 合并所有属性的扁平化结果
    }[keyof T] 
  : 
    // 原始类型返回对应路径的键值对
    Path extends never ? never : { [key in Path]: T }

// 主类型:支持联合类型的对象扁平化入口
type Flatten<T> = Merge<
  // 利用分布式条件类型处理联合,每个分支单独处理后合并
  T extends any ? FlattenSingle<T> : never
>

使用示例

针对你提供的接口测试效果:

interface Foo {
  foo: string
  bar?: number
  nested: {
    foo: string,
    deeplyNested: {
      bar?: number
    }
  }
  union: string | {
    foo: string,
    bar?: number
  }
}

// 生成的扁平化类型和你要求的效果完全一致
type FooFlattened = Flatten<Foo>

最终FooFlattened的展开结果为:

{
  foo: string;
  bar?: number | undefined;
  "nested.foo": string;
  "nested.deeplyNested.bar"?: number | undefined;
  union: string;
  "union.foo": string;
  "union.bar"?: number | undefined;
}

支持特性

  • 支持任意层级的对象嵌套,自动拼接完整属性路径作为键名
  • 自动处理所有联合类型成员,不同联合分支产生的扁平化键会合并到最终类型中
  • 完整保留原接口的可选属性标记,可选属性扁平化后依然为可选状态
  • 兼容所有基础原始类型(string/number/boolean等)

扩展说明

如果需要支持数组类型,可以在FlattenSingle类型中新增数组分支的处理逻辑,按需实现数组下标的路径拼接即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 21:39:03