如何编写支持泛型/重载的类型安全柯里化记录字段映射函数
类型安全的柯里化记录字段映射函数实现问题
我想编写一个柯里化函数,以类型安全的方式映射记录的每个字段,但不知道如何使用映射类型处理字段映射函数(fn: TFunc)为泛型或重载函数的情况。
export const mapRecordFields = <TFunc extends (x: any) => any> ( fn: TFunc, // 可能是泛型或重载函数 ) => <TRecord extends Record<string, any>> ( record: TRecord, ): { [P in keyof TRecord]: /* ??? */ } => { /* 忽略实现细节 */ }; const identity = <T> (x: T): T => x; const toSingleElementArr = <T> (x: T): [T] => [x] const structure = { x: 1, y: 'qwe', } as const; const result1 = mapRecordFields(identity)(structure); // 期望推断类型:{x: 1, y: 'qwe'} const result2 = mapRecordFields(toSingleElementArr)(structure); // 期望推断类型:{x: [1], y: ['qwe']}
我尝试了StackOverflow上的相关解决方案,但仍无法让result的类型正确推断,请问是否有可行的解决方法?
解决方案
要实现类型安全的映射,核心是利用TypeScript的条件类型和泛型推断,让映射函数的返回类型能精准作用于记录的每个字段。修改后的函数定义如下:
export const mapRecordFields = <TFunc> ( fn: TFunc ) => <TRecord extends Record<string, unknown>> ( record: TRecord ): { [P in keyof TRecord]: TFunc extends (x: infer X) => infer Y ? (TRecord[P] extends X ? Y : never) : never } => { // 示例实现逻辑(可根据需求调整) const mapped: any = {}; for (const key in record) { mapped[key] = fn(record[key]); } return mapped; };
关键细节:
- 通过
TFunc extends (x: infer X) => infer Y提取映射函数的输入类型X和输出类型Y - 对记录的每个字段
TRecord[P],校验其是否符合X的类型约束,返回对应的Y类型 - 针对泛型映射函数,TypeScript会自动为每个字段的具体类型推断出正确的返回值类型
测试验证:
const identity = <T> (x: T): T => x; const toSingleElementArr = <T> (x: T): [T] => [x] const structure = { x: 1, y: 'qwe', } as const; const result1 = mapRecordFields(identity)(structure); // 实际推断类型:{ readonly x: 1; readonly y: "qwe"; } const result2 = mapRecordFields(toSingleElementArr)(structure); // 实际推断类型:{ readonly x: [1]; readonly y: ["qwe"]; }
如果映射函数是重载类型,TypeScript也会根据传入字段的具体类型匹配对应的重载签名,保证类型安全。
内容的提问来源于stack exchange,提问作者SimpleV
相关产品推荐
相关产品推荐

