为支持泛型Schema的转换函数添加正确TypeScript类型
解决方案:为字段映射函数添加TypeScript泛型类型约束
核心需求
将单字符命名的API响应类型(如AB)自动映射到可读性更强的目标类型(如XY),同时为映射函数convert及映射规则mapping添加严格的TypeScript类型约束,消除any类型。
类型定义与实现
1. 定义嵌套映射类型Mapping<T, U>
该类型约束mapping对象的结构:
- 键必须是原始类型
T的所有属性名 - 值分为两种情况:
- 直接映射:目标类型
U中的属性名,且原始属性类型与目标属性类型完全匹配 - 嵌套映射:数组
[目标属性名, 子映射对象],仅当原始属性和目标属性均为对象类型时生效
- 直接映射:目标类型
type Mapping<T extends object, U extends object> = { [OriginalKey in keyof T]: // 直接映射:匹配U中类型一致的属性名 { [K in keyof U]: T[OriginalKey] extends U[K] ? K : never }[keyof U] // 嵌套映射:仅当原始属性和目标属性都是对象时允许 | (T[OriginalKey] extends object ? { [K in keyof U]: U[K] extends object ? [K, Mapping<T[OriginalKey], U[K]>] : never }[keyof U] : never); };
2. 实现泛型convert函数
利用Mapping<T, U>约束参数,确保输入输出类型严格匹配,消除any:
function convert<T extends object, U extends object>( obj: T, mapping: Mapping<T, U> ): U { const ret = {} as U; // 断言entries类型为[keyof T, 对应映射值],确保类型安全 for (const [originalKey, mappingValue] of Object.entries(mapping) as [keyof T, typeof mapping[keyof T]][]) { const originalValue = obj[originalKey]; if (Array.isArray(mappingValue)) { // 处理嵌套映射 const [newKey, subMapping] = mappingValue; ret[newKey] = convert(originalValue as Extract<T[keyof T], object>, subMapping) as U[keyof U]; } else { // 处理直接映射 const newKey = mappingValue as keyof U; ret[newKey] = originalValue as U[keyof U]; } } return ret; }
完整使用示例
interface AB { a: string; b: C; } interface C { c: number; } interface XY { x: string; y: Z; } interface Z { z: number; } const abc: AB = { a: '...', b: { c: 123, }, }; // 映射规则自动校验类型,不符合约束会报错 const ab_xy: Mapping<AB, XY> = { a: 'x', b: ['y', { c: 'z' }] }; // 自动推导返回类型为XY,无需手动标注 const actual_xyz = convert(abc, ab_xy); const expected_xyz: XY = { x: '...', y: { z: 123, } }; console.log(' abc: %o', abc); console.log('expected_xyz: %o', expected_xyz); console.log(' actual_xyz: %o', actual_xyz);
关键特性
- 类型安全:如果映射规则写错(比如把
a映射到y),TypeScript会直接报错 - 自动推导:调用
convert时无需手动指定泛型参数,TypeScript会根据输入自动推导T和U - 支持嵌套:递归处理多层嵌套对象的映射
内容的提问来源于stack exchange,提问作者Vito De Tullio
相关产品推荐
相关产品推荐

