TypeScript深度驼峰转蛇形函数:泛型返回类型优化问题
解决TypeScript驼峰转蛇形深度转换函数的返回类型问题
问题分析
你当前的实现通过手动指定泛型I和O,返回类型设为I | O,导致TypeScript无法区分输入是基本类型(返回I)还是对象/数组(返回O),最终推断出联合类型,无法正确识别转换后的具体类型。
解决方案
通过类型工具函数自动映射驼峰类型到蛇形类型,结合条件类型让函数返回明确的转换后类型,无需手动指定输出泛型。
1. 定义类型转换工具
先实现两个类型工具,用于将驼峰命名的类型深度转换为蛇形命名:
// 单个驼峰字符串转蛇形字符串的类型工具 type CamelToSnakeCase<S extends string> = S extends `${infer Prefix}${infer Capital}${infer Suffix}` ? Capital extends Uppercase<Capital> ? `${Lowercase<Prefix>}_${Lowercase<Capital>}${CamelToSnakeCase<Suffix>}` : `${Prefix}${CamelToSnakeCase<`${Capital}${Suffix}`>}` : S; // 深度转换对象/数组为蛇形命名的类型工具 type DeepSnakeCase<T> = T extends Array<infer U> ? Array<DeepSnakeCase<U>> : T extends object ? { [K in keyof T as CamelToSnakeCase<string & K>]: DeepSnakeCase<T[K]> } : T;
2. 重写转换函数
利用上述类型工具,让函数的返回类型自动匹配输入类型的蛇形转换结果:
function deepConvertToSnakeCase<T>(item: T): DeepSnakeCase<T> { // 处理数组:递归转换每个元素 if (Array.isArray(item)) { return item.map(el => deepConvertToSnakeCase(el)) as DeepSnakeCase<T>; } // 处理非对象/空值:直接返回原值 if (typeof item !== 'object' || item === null) { return item as DeepSnakeCase<T>; } // 处理对象:转换键为蛇形,递归处理值 return Object.fromEntries( Object.entries(item).map(([key, value]) => [ key.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase(), deepConvertToSnakeCase(value) ]) ) as DeepSnakeCase<T>; }
3. 使用示例
现在调用函数时,TypeScript会自动推断出正确的蛇形类型:
interface CamelCaseObject { keyItem: 'value'; keyItemAlso: 'value'; nestedObj: { anotherKey: number; }; itemList: { listItem: boolean; }[]; } const data: CamelCaseObject = { keyItem: 'value', keyItemAlso: 'value', nestedObj: { anotherKey: 123 }, itemList: [{ listItem: true }] }; const convertedData = deepConvertToSnakeCase(data); // convertedData类型自动推断为: // { // key_item: 'value'; // key_item_also: 'value'; // nested_obj: { // another_key: number; // }; // item_list: { // list_item: boolean; // }[]; // }
关键改进点
- 移除了手动指定的输出泛型
O,改用DeepSnakeCase<T>自动映射输入类型到输出类型 - 明确区分了数组、对象、基本类型的处理逻辑,返回类型不再是模糊的联合类型
- 支持嵌套对象和数组的深度转换,类型推断完全同步
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

