如何从泛型函数映射中获取指定函数的返回类型?
问题描述
我有一个包含多态泛型函数的字典,其中的函数接受相同参数但返回不同结果:
const dict = { one: { foo<A>(a: A) { return [a] as const } }, two: { foo<A>(a: A) { return [a, a] as const } }, three: { foo<A>(a: A) { return [a, a, a] as const } } } type MapType = typeof dict // 注:原代码中`type Map = typeof map`应为笔误,修正为`typeof dict`
我希望通过辅助工具函数获取该字典中函数的返回类型,于是写了如下代码:
const wrapper = <N extends keyof MapType, A>() => { const fn = (() => {}) as unknown as MapType[N]['foo'] return null as unknown as ReturnType<typeof fn<A>> }
但尝试获取指定函数的返回类型时(比如传入参数7,获取'two'对应的返回类型),得到的是所有函数返回类型的联合类型,而非预期的单一类型:
// 实际返回类型: readonly [7] | readonly [7, 7] | readonly [7, 7, 7] // 预期返回类型: readonly [7, 7] type Result = typeof wrapper<'two', 7>
问题在于即使传入单一的键值,泛型参数N仍被视为联合类型,导致返回所有可能的结果。另外需要说明的是,我无法访问dict对象本身,它来自第三方库。
解决方案
问题的核心在于,当使用MapType[N]['foo']时,TypeScript无法正确将泛型函数的具体实例与N的具体值绑定,而是将所有可能的foo函数视为联合类型处理。以下是两种可行的解决方式:
方案1:纯类型工具(推荐)
不需要编写值级别的wrapper函数,直接通过类型映射和条件类型提取目标返回类型:
type MapType = typeof dict; type GetFooReturnType<N extends keyof MapType, A> = MapType[N]['foo'] extends (a: A) => infer R ? R : never; // 测试:获取'two'对应foo函数传入7的返回类型 type Result = GetFooReturnType<'two', 7>; // 结果:readonly [7, 7]
方案2:修正值级别的wrapper函数
如果必须保留wrapper函数的形式,需要拆分泛型参数,先固定N再传入A,确保TypeScript能正确识别对应N的具体foo函数:
type MapType = typeof dict; const wrapper = <N extends keyof MapType>() => { return <A>() => { type TargetFn = MapType[N]['foo']; return null as unknown as TargetFn extends (a: A) => infer R ? R : never; }; }; // 测试 type Result = ReturnType<ReturnType<typeof wrapper<'two'>><'7'>>; // 结果:readonly [7, 7]
原理说明
- 方案1直接通过条件类型
infer提取指定foo函数在传入参数A时的返回类型,完全在类型层面处理,避免了值级别的类型混淆。 - 方案2将泛型参数拆分两次传入,先锁定
N对应的具体foo函数,再传入参数类型A,确保TypeScript不会将所有foo函数视为联合类型处理。
内容的提问来源于stack exchange,提问作者aiven715
相关产品推荐
相关产品推荐

