You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript模板字面量实现Pub/Sub子事件时泛型约束失效问题

问题原因

你当前的泛型约束失效核心是TypeScript的泛型推导逻辑限制:你声明的subscribeToSubEvent的泛型参数E默认约束为ChatEvent联合类型,当你传入具体事件字符串时,TS不会基于EventWithSubEvent<E>反向收窄E的取值范围,而是直接将E推导为完整的ChatEvent联合("connect" | "disconnect"),因此出现两个问题:

  • 回调payload被推导为所有事件payload的联合类型
  • 不会校验子事件和父事件的匹配关系,非法组合也能通过校验
解决方案

最简洁且性能最优的方案是先预构造全量合法事件与payload的映射表,直接基于映射表做类型约束:

// 构造全量合法事件映射
type FullEventMap = {
  [E in ChatEvent as EventWithSubEvent<E>]: ChatEvents[E]
}

// 重写订阅函数,直接约束事件为映射表的key
declare function subscribeToSubEvent<E extends keyof FullEventMap>(
  event: E,
  callback: (payload: FullEventMap[E]) => void
): void;

修改后即可解决所有问题:

  1. 传入合法事件"connect:general"时,payload会正确推导为{ user: string }
  2. 传入非法事件"connect:voice"时,会直接触发类型错误,提示该事件不在合法范围内

你还可以直接合并为一个统一的订阅函数,覆盖根事件和带子事件的所有场景,符合你最开始期望的调用语法:

declare function on<E extends keyof FullEventMap>(
  event: E,
  callback: (payload: FullEventMap[E]) => void
): void;

// 两种调用都正常触发类型校验
on("connect", payload => { /* payload为connect事件类型 */ })
on("connect:general", payload => { /* payload同样为connect事件类型 */ })
on("disconnect:voice", payload => { /* payload为disconnect事件类型 */ })

内容的提问来源于stack exchange,提问作者Slava Knyazev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 23:54:03