TypeScript如何定义返回函数集合中函数执行结果的函数类型
问题解答
核心原因
你遇到的类型问题本质是TypeScript泛型约束的设计逻辑导致的:
- 泛型的
extends约束仅代表最低匹配要求,而非对泛型的精确类型限制:
你定义的T extends Partial<Record<ProductName, () => any>>只要求T中属于ProductName枚举范围内的属性为可选的无参函数,但并没有限制T不能包含ProductName之外的额外属性,这些额外属性的类型可以是任意值(比如字符串、数字等非函数类型)。
因此在泛型定义阶段,TypeScript无法100%确认T[keyof T]一定是函数类型——因为keyof T包含了所有T的键,其中可能存在非ProductName范围的键,对应的值不是函数。
为什么变量a的类型可以正确推导
当你实际调用onAnyProduct函数时,传入的是一个没有额外属性的对象字面量,TypeScript会根据你传入的实参做精确的类型推断:
此时T的类型被精确推导为{ product1: () => string, product2: () => {} },T的键只有product1和product2,对应的值都是函数,因此ReturnType<T[keyof T]>可以正确计算为string | {},再加上可选链带来的undefined,最终a的类型就是string | {} | undefined。
修复方案
如果要让TypeScript在泛型定义阶段就识别T[keyof T]是函数类型,可以调整泛型定义,限制T的键只能是ProductName的子集:
export function onAnyProduct<K extends ProductName, T extends Record<K, () => any>>( productCallbacks: T ): ReturnType<T[K]> | undefined { const name = detectProduct() as K; const callback = productCallbacks[name]; return callback?.(); }
调整后泛型K被限制为ProductName的子集,T的键只能是K范围内的值,所有属性都符合函数类型,T[K]必然是函数类型,不会再出现类型问题。
内容的提问来源于stack exchange,提问作者Mehdi Hoseini
相关产品推荐
相关产品推荐

