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

使用TypeScript泛型作为索引:事件监听器类型定义疑问

事件监听器泛型类型的类型检查问题

你写的这段代码思路是对的——你预期connected事件的回调会触发类型错误完全合理,因为connected对应的回调参数被定义为number类型,而number根本没有stack属性,访问err.stack属于明显的类型不匹配。

先确认问题核心

在你的代码里:

type Name = "error" | "connected";
type Callback = {
  error: (err: Error) => void,
  connected: (err: number) => void,
};
function on<T extends Name>(eventName: T, callback: Callback[T]): void { }

// 这里err是Error类型,访问stack没问题
on("error", (err) => err.stack);
// 这里err应该是number类型,访问stack理应报错
on("connected", (err) => err.stack);

正常情况下,TypeScript会给第二个on调用抛出类型错误:Property 'stack' does not exist on type 'number'。如果你的环境没触发这个错误,大概率是TypeScript的配置不够严格——检查下tsconfig.json里是否开启了strict: true(至少要开启noImplicitAny),严格模式下类型推断才会精准生效。

优化你的类型定义

虽然初始代码的泛型思路可行,但可以用更清晰的方式定义事件与回调的映射,让类型检查更直观:

// 用元组统一定义每个事件的回调参数列表
type EventMap = {
  error: [Error],
  connected: [number]
};

// 直接基于EventMap的键做泛型约束
function on<K extends keyof EventMap>(
  eventName: K,
  callback: (...args: EventMap[K]) => void
): void {}

// 合法调用:err是Error类型,stack属性存在
on("error", (err) => console.log(err.stack));

// 类型错误:number类型没有stack属性(TypeScript会直接标出)
on("connected", (err) => console.log(err.stack));

这种方式的优势在于,EventMap可以很方便地扩展新事件,而且回调的参数类型会被TypeScript自动精准推断,不会出现模糊的情况。

总结

你的初始代码逻辑没问题,类型错误没触发的话优先检查TS配置;如果想让类型系统更健壮,推荐用EventMap+元组的方式来定义事件回调的类型映射。

内容的提问来源于stack exchange,提问作者ed'

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:36:41