TypeScript mapKeys函数类型报错修复及返回键类型推断实现
修复
mapKeys函数的TypeScript类型错误并实现键类型推断 问题描述
我编写了一个mapKeys函数,它接收重命名函数和对象,根据重命名函数对对象的键进行重命名,代码如下:
export default function mapKeys<T extends { [s: string]: T } | ArrayLike<T>>( renameFunction: (key: string) => string, object: T, ): T { return Object.fromEntries( Object.entries(object).map(([key, value]) => [renameFunction(key), value]), ); }
使用示例:
mapKeys(key => key.toUpperCase(), { a: 1, b: 2 }); // => { A: 1, B: 2 }
但该函数存在TypeScript类型报错:
- 函数定义处:
Type '{ [k: string]: T; }' is not assignable to type 'T'... - 调用处:
Type 'number' is not assignable to type '{ a: number; b: number; }'
我需要修复这些错误,同时让TypeScript能够推断返回对象的键类型。例如当重命名函数为const rename = (a: string) => ${a}Error``,对象为{ email: 'foo' }时,TypeScript能识别返回对象的键为emailError。
我曾尝试改成以下写法,虽然能编译,但会丢失对象键的类型信息,无法推断返回对象的具体形状:
export default function mapKeys( renameFunction: (key: string) => string, object: object, ): object { return Object.fromEntries( Object.entries(object).map(([key, value]) => [renameFunction(key), value]), ); }
解决方案
要实现类型安全且支持键类型推断的mapKeys,需要利用TypeScript的模板字面量类型和泛型约束,让编译器跟踪键的转换关系:
1. 完整实现代码
// 定义键重映射后的对象类型 type MapKeys<T extends object, R extends string> = { [K in keyof T as R]: T[K]; }; export default function mapKeys< T extends object, R extends string, F extends (key: Extract<keyof T, string>) => R >( renameFunction: F, object: T, ): MapKeys<T, ReturnType<F>> { return Object.fromEntries( Object.entries(object).map(([key, value]) => [renameFunction(key as Extract<keyof T, string>), value]), ) as MapKeys<T, ReturnType<F>>; }
2. 验证效果
测试场景1:键转大写
const result1 = mapKeys(key => key.toUpperCase(), { a: 1, b: 2 }); // TypeScript自动推断返回类型:{ A: number; B: number }
测试场景2:键添加固定后缀
const rename = (a: string) => `${a}Error` as const; const result2 = mapKeys(rename, { email: 'foo' }); // TypeScript自动推断返回类型:{ emailError: string }
关键说明
MapKeys类型:通过as关键字实现键的重映射,将原对象的键K替换为目标键类型R- 泛型
F:约束重命名函数的参数为输入对象的字符串键,返回值为新键类型,确保类型推断的准确性 Extract<keyof T, string>:处理对象键可能包含number或symbol的情况,仅保留字符串类型的键用于重命名- 类型断言:
Object.fromEntries默认返回宽松的{[key: string]: T[K]}类型,通过断言转为我们定义的精确键类型
内容的提问来源于stack exchange,提问作者J. Hesters
相关产品推荐
相关产品推荐

