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
相关产品推荐
相关产品推荐

