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

TypeScript对象扁平化类型定义及方法类型推导问题

问题:嵌套颜色对象扁平化的TypeScript类型推导优化

需求背景

需要实现嵌套颜色对象的扁平化逻辑:

  • 属性值为HEX格式字符串时直接保留
  • 属性值为包含HEX值的子对象时:
    • 子对象的DEFAULT属性值映射为父属性名
    • 子对象的其他属性映射为父属性名-子属性名格式

JavaScript逻辑已实现,但TypeScript自定义类型存在问题:直接定义类型(如ExampleConversion)时能正确推导具体类型,但调用flatColorsSettings方法时,变量ExampleMethodConversion的类型仅显示泛型而非具体推导结果,需要优化类型实现方案。

输入输出示例

输入对象

const from = {
  red: '#red-val',
  green: {
    200: '#green-200-val',
    300: '#green-300-val',
    DEFAULT: '#green-default-val',
  },
}

期望输出对象

const to = {
  red: '#red-val',
  green: '#green-default-val',
  'green-200': '#green-200-val',
  'green-300': '#green-300-val',
}

现有泛型类型代码

type HEX_VAL = `#${string}`;

type Props = {
  [K in string]:
    | HEX_VAL
    | {
        [IK in string]: HEX_VAL;
      };
};

type ConvertChildKey<K extends string, P extends string> = K extends 'DEFAULT'
  ? P
  : `${P}-${K}`;

type FlatColorKeys<P extends Props> = {
  [K in keyof P]: P[K] extends Props
    ? //@ts-ignore
      ConvertChildKey<keyof P[K], K extends string ? K : never>
    : K;
}[keyof P];

type FlatColorsSettingsT<T extends Props> = Record<FlatColorKeys<T>, HEX_VAL>;

解决方案

要解决方法调用时的类型推导问题,核心是让TypeScript精准推断输入对象的字面量类型,并在泛型中保留具体的键和结构信息,而非宽泛的Props约束。

优化后的类型实现

type HEX_VAL = `#${string}`;

// 定义输入类型:允许属性值为HEX或包含HEX的对象
type ColorInput = 
  HEX_VAL | { [K in string]: HEX_VAL };

// 转换子键为目标格式
type ConvertChildKey<K extends string, P extends string> = 
  K extends 'DEFAULT' ? P : `${P}-${K}`;

// 递归扁平化键
type FlatColorKeys<T> = 
  T extends HEX_VAL 
    ? never // 纯HEX值没有子键,跳过
    : {
        [K in keyof T]: 
          T[K] extends HEX_VAL 
            ? K // 直接保留当前键
            : K extends string 
              ? ConvertChildKey<keyof T[K], K> // 处理子对象的键
              : never;
      }[keyof T];

// 生成扁平化后的类型
type FlatColorsSettingsT<T> = Record<FlatColorKeys<T>, HEX_VAL>;

// 优化方法的泛型约束,让TypeScript推断输入的字面量类型
function flatColorsSettings<T extends Record<string, ColorInput>>(input: T): FlatColorsSettingsT<T> {
  // 已实现的JavaScript逻辑
  const result: Record<string, HEX_VAL> = {};
  for (const key in input) {
    const val = input[key];
    if (typeof val === 'string') {
      result[key] = val;
    } else {
      for (const childKey in val) {
        const targetKey = childKey === 'DEFAULT' ? key : `${key}-${childKey}`;
        result[targetKey] = val[childKey];
      }
    }
  }
  return result as FlatColorsSettingsT<T>;
}

效果验证

现在调用flatColorsSettings时,TypeScript会自动推导具体的输出类型:

const from = {
  red: '#red-val',
  green: {
    200: '#green-200-val',
    300: '#green-300-val',
    DEFAULT: '#green-default-val',
  },
} as const; // 使用as const固定输入类型,提升推导精度

const converted = flatColorsSettings(from);
// converted的类型会被推导为:
// {
//   red: `#${string}`;
//   green: `#${string}`;
//   "green-200": `#${string}`;
//   "green-300": `#${string}`;
// }

关键优化点

  • 移除宽泛的Props约束:改用更精准的泛型约束T extends Record<string, ColorInput>,让TypeScript能捕捉输入对象的具体键和结构。
  • 使用as const固定输入类型:确保输入对象的键和值被推断为字面量类型,而非宽泛的string,提升类型推导的精度。
  • 优化键处理逻辑:重构FlatColorKeys类型,更清晰地处理纯HEX值和子对象的情况,移除@ts-ignore注释。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:01:12