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

TypeScript中复合枚举式常量对象的类型安全动态重映射问题

复合枚举式常量对象类型安全重映射的优化方案

一、修复条件类型分支误判问题

  • 用字面量类型精准区分$$key
    先定义专属的$$key字面量类型,替代模糊的字符串判断:
    type $$Key = '$$key';
    
    然后在条件类型里用extends $$Key做精准匹配,避免联合类型或其他字符串触发错误分支:
    type RemapSingleKey<T, K extends keyof T, IKey, OKey> = 
      IKey extends $$Key 
        ? OKey extends $$Key 
          ? K  // 输入输出都是$$key,保留原键
          : T[K][OKey]  // 输入$$key,输出枚举键,取对应值
        : OKey extends $$Key
          ? T[K][IKey]  // 输入枚举键,输出$$key,取输入对应值作为键
          : T[K][IKey][OKey];  // 输入输出都是枚举键,嵌套取值
    
  • 用分布式条件类型处理联合类型
    把泛型参数IKey和OKey约束为keyof T[keyof T] | $$Key,确保条件类型对每个联合成员单独判断,不会出现分支穿透。

二、CompoundRecord的替代方案

CompoundRecord不是唯一可靠的访问方式,试试用泛型约束+精准索引来替代:

  • 先定义复合枚举的标准结构类型,明确约束:
    type CompoundEnum<T> = T extends Record<string, Record<string, unknown>> ? T : never;
    
  • 在工具类型里直接用这个约束,访问T[K][IKey]时,通过泛型确保K是keyof T,IKey是keyof T[K] | $$Key,完全不需要宽泛的CompoundRecord<any>,类型检查更严格:
    type RemapCompoundEnum<T extends CompoundEnum<T>, IKey, OKey> = {
      [K in keyof T]: RemapSingleKey<T, K, IKey, OKey>;
    };
    

三、提升工具可靠性与精简性的建议

  • 抽离公共逻辑:把重复的分支判断封装成RemapSingleKey这类辅助类型,避免代码冗余,后续修改也更方便。
  • 添加类型测试用例:针对4种分支场景写测试,验证类型推导是否正确,比如:
    // 测试1:输入$$key,输出$$key → 保留原键
    type Test1 = RemapCompoundEnum<{ foo: { id: 'FOO', name: 'Foo' } }, '$$key', '$$key'>;
    // 预期:{ foo: 'foo' }
    
    // 测试2:输入$$key,输出枚举键 → 映射对应值
    type Test2 = RemapCompoundEnum<{ foo: { id: 'FOO', name: 'Foo' } }, '$$key', 'id'>;
    // 预期:{ foo: 'FOO' }
    
  • 缩小泛型约束范围:把IKey和OKey约束为keyof T[keyof T] | $$Key,别用any,减少类型推导的不确定性。
  • 用TS 5.x特性强化约束:如果使用TypeScript 5.0+,可以用const类型参数和satisfies关键字,确保传入的常量对象符合复合枚举结构:
    const MyEnum = {
      foo: { id: 'FOO', name: 'Foo' },
      bar: { id: 'BAR', name: 'Bar' }
    } as const satisfies CompoundEnum<typeof MyEnum>;
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:05:17