TypeScript泛型动态函数参数:如何获取第二个参数的正确类型?
TypeScript泛型函数内部无法根据第一个参数推断第二个参数类型的解决方法
我参考教程在TypeScript中用泛型实现了动态参数的sendEvent函数,外部调用时参数类型符合预期,但函数内部第二个参数eventPayload的类型始终是unknown。如何根据第一个参数的类型,在函数内部获取第二个参数的正确类型?
相关代码:
export type Event = | { type: "LOG_IN"; payload: { userId: string } } | { type: "SIGN_OUT" }; const sendEvent = <Type extends Event["type"]>( ...args: Extract<Event, { type: Type }> extends { payload: infer TPayload } ? [type: Type, payload: TPayload] : [type: Type] ) => { const eventType = args[0]; // 类型为 "LOG_IN" | "SIGN_OUT" const eventPayload = args[1]; // 类型为 unknown // 如何让eventPayload获得对应payload的正确类型? };
解决方案1:使用类型守卫窄化类型
在函数内部通过判断eventType的具体值,TypeScript会自动关联并窄化eventPayload的类型:
const sendEvent = <Type extends Event["type"]>( ...args: Extract<Event, { type: Type }> extends { payload: infer TPayload } ? [type: Type, payload: TPayload] : [type: Type] ) => { const eventType = args[0]; if (eventType === "LOG_IN") { const eventPayload = args[1]; // 类型自动推断为 { userId: string } console.log(eventPayload.userId); // 无类型错误 } else if (eventType === "SIGN_OUT") { const eventPayload = args[1]; // 类型自动推断为 undefined // 无需处理payload } };
解决方案2:重构为对象参数(推荐)
将参数改为单个对象形式,TypeScript的类型推断逻辑会更清晰,内部直接解构就能拿到对应类型:
export type Event = | { type: "LOG_IN"; payload: { userId: string } } | { type: "SIGN_OUT" }; const sendEvent = <E extends Event>(event: E) => { const { type: eventType, payload: eventPayload } = event; if (eventType === "LOG_IN") { console.log(eventPayload.userId); // 类型正确 } }; // 调用示例 sendEvent({ type: "LOG_IN", payload: { userId: "user_123" } }); sendEvent({ type: "SIGN_OUT" });
解决方案3:定义事件类型映射
提前构建事件类型到payload的映射关系,通过泛型直接获取对应类型:
export type Event = | { type: "LOG_IN"; payload: { userId: string } } | { type: "SIGN_OUT" }; // 建立事件类型与payload的映射 type EventPayloadMap = { [E in Event as E["type"]]: E extends { payload: infer P } ? P : undefined; }; const sendEvent = <Type extends Event["type"]>( ...args: EventPayloadMap[Type] extends undefined ? [type: Type] : [type: Type, payload: EventPayloadMap[Type]] ) => { const eventType = args[0]; const eventPayload = args[1] as EventPayloadMap[Type]; if (eventType === "LOG_IN") { console.log(eventPayload.userId); // 类型正确 } };
问题原因
原写法中,泛型Type在函数内部是宽泛的联合类型("LOG_IN" | "SIGN_OUT"),TypeScript无法从元组args中建立args[0]和args[1]的类型关联,导致args[1]被推断为unknown。通过上述三种方案,能让TypeScript明确参数之间的类型依赖关系。
内容的提问来源于stack exchange,提问作者PDM
相关产品推荐
相关产品推荐

