TypeScript嵌套泛型问题:参数被解析为交叉类型而非联合类型
解决TypeScript泛型钩子中交叉类型替代联合类型的报错问题
问题原因
TypeScript在泛型函数registerHumanHook中无法正确窄化泛型参数K对应的HumanHook[K]类型,错误地将其解析为所有HumanHookName对应类型的交叉类型(而非预期的单个匹配类型),导致参数类型不兼容报错。
解决方案
在初始化humanHooks[name]时,使用精确的类型断言将对象指定为HumanHook[K],既保留TypeScript的类型校验能力,又能修正交叉类型的错误推断:
interface HumanFunctionTypeMap { eat: { name: string; diet: boolean; vegan: boolean; }; drink: Array<{ diet: boolean; regular: boolean; soda: boolean; }>; sleep: { dream: boolean; snooze: boolean; }; } type HumanHookName = keyof HumanFunctionTypeMap; type HumanHook = { [K in HumanHookName]?: { hooks: Array<(args: HumanFunctionTypeMap[K]) => void>; handler: (args: HumanFunctionTypeMap[K]) => void; }; }; interface RegisterHumanHook { <K extends HumanHookName>(name: K, hook: (args: HumanFunctionTypeMap[K]) => void): void; } const humanHooks: HumanHook = {}; export const registerHumanHook: RegisterHumanHook = (name, hook) => { if (!humanHooks[name]) { // 关键修改:用精确断言指定当前K对应的钩子类型 humanHooks[name] = { hooks: [], handler: args => { humanHooks[name]?.hooks.forEach(hook => hook(args)); } } as HumanHook[K]; } humanHooks[name]?.hooks?.push(hook); };
方案说明
as HumanHook[K]明确告诉TypeScript,当前初始化的对象完全匹配泛型参数K对应的钩子类型,而非所有可能类型的交叉集合。- 相比宽泛的类型断言(如
as any或as HumanHookName),该方式保留了对hooks和handler参数的严格类型校验,确保后续添加的钩子与当前name对应的参数类型一致。
可选优化
若想进一步增强类型追踪能力,可以用泛型辅助函数初始化humanHooks,让TypeScript更清晰地识别每个key的类型:
function createHumanHooks<T extends HumanHook = HumanHook>(): T { return {} as T; } const humanHooks = createHumanHooks();
内容的提问来源于stack exchange,提问作者roi467
相关产品推荐
相关产品推荐

