TypeScript中如何从判别式联合回调推断映射的返回类型
TypeScript中如何从判别式联合回调推断映射的返回类型
嘿,这个需求我之前折腾过好一阵!咱们直接用你给的例子来一步步拆解,很快就能搞懂怎么实现~
首先,你现在有这么一个函数:
function createRecord(createValue: (input: 'a' | 'b') => unknown): Record<'a' | 'b', unknown> { // 这里是函数的基础实现,比如遍历生成对应记录 return { a: createValue('a'), b: createValue('b') } as Record<'a' | 'b', unknown>; }
但你希望调用的时候,传入带条件类型的泛型回调后,TypeScript能自动推断出返回的x类型是{ a: 'A', b: 'B' },而不是现在这种宽泛的Record<'a' | 'b', unknown>,就像你写的这段调用代码:
const x = createRecord(<Input extends 'a' | 'b'>(input: Input): Input extends 'a' ? 'A' : 'B' => { return input === 'a' ? 'A' : 'B'; });
那问题出在哪呢?原来的createRecord函数签名太“死板”了,它没办法识别到回调里的条件类型是和每个输入键一一对应的,只能返回最宽泛的unknown值类型。
要解决这个问题,我们需要把createRecord改成泛型函数,让它能关联输入的联合类型和回调的返回类型,具体写法如下:
// 泛型函数签名,让TypeScript能精准推断映射关系 function createRecord<K extends string | number | symbol>( createValue: <Key extends K>(key: Key) => unknown ): { [P in K]: ReturnType<(typeof createValue) extends (k: P) => infer R ? R : never> }; // 函数实现部分,用类型断言绕开TypeScript的推断限制 function createRecord<K extends string | number | symbol>( createValue: (key: K) => unknown ) { const result = {} as Record<K, unknown>; // 这里需要拿到K对应的所有键,比如K是字面量联合时,可以手动传入或用类型工具提取 const keys = ['a', 'b'] as K[]; for (const key of keys) { result[key] = createValue(key); } return result; }
现在再调用这个函数,TypeScript就能准确推断出x的类型啦:
const x = createRecord(<Input extends 'a' | 'b'>(input: Input): Input extends 'a' ? 'A' : 'B' => { return input === 'a' ? 'A' : 'B'; }); // 此时x的类型会被正确推断为 { a: 'A', b: 'B' }
核心逻辑其实就是:把原来固定的Record<'a' | 'b', unknown>换成泛型映射类型,让TypeScript能把回调里每个输入键对应的返回类型,一一映射到最终返回对象的每个属性上,这样就能从判别式联合的回调里自动推断出精准的返回类型了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

