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

TypeScript中带继承的命名事件/回调处理器实现问题

问题描述

我实现了一个NamedHandler类,通过泛型传入允许的事件/处理器名称列表,单类场景下使用正常。但尝试继承该类并扩展允许的处理器名称时,找不到可行的实现方式。

原类核心代码如下:

class NamedHandler<T extends string> {
  handlers: Record<T, (...args: any[]) => void> = {} as Record<T, (...args: any[]) => void>;

  on(event: T, handler: (...args: any[]) => void) {
    this.handlers[event] = handler;
  }

  emit(event: T, ...args: any[]) {
    this.handlers[event]?.(...args);
  }
}

// 期望扩展出支持'foo'|'bar'|'baz'的子类,但直接继承无法添加新事件名
class ExtendedHandler extends NamedHandler<'foo' | 'bar'> {
  // 如何添加'baz'作为允许的事件名?
}
解决方案

以下是几种可行的实现方式:

1. 子类传入扩展后的联合泛型

直接在继承时将父类基础事件名与新事件名合并,这是最简单直接的固定扩展方案:

class ExtendedHandler extends NamedHandler<'foo' | 'bar' | 'baz'> {
  // 可添加子类专属逻辑
  logExtension() {
    console.log("已扩展支持baz事件");
  }
}

const handler = new ExtendedHandler();
handler.on('foo', () => {}); // ✅ 合法
handler.on('baz', () => {}); // ✅ 合法
handler.emit('bar'); // ✅ 合法

2. 子类支持动态扩展泛型

如果需要子类能灵活指定任意新增事件名,可让子类也接受泛型,并与父类基础事件名做联合:

class NamedHandler<T extends string> {
  handlers: Record<T, (...args: any[]) => void> = {} as Record<T, (...args: any[]) => void>;

  on(event: T, handler: (...args: any[]) => void) {
    this.handlers[event] = handler;
  }

  emit(event: T, ...args: any[]) {
    this.handlers[event]?.(...args);
  }
}

// 子类泛型默认never,代表不额外扩展事件
class ExtendedHandler<T extends string = never> extends NamedHandler<'foo' | 'bar' | T> {
}

// 使用时指定额外事件'baz'
const handler = new ExtendedHandler<'baz'>();
handler.on('foo', () => {}); // ✅ 合法
handler.on('baz', () => {}); // ✅ 合法

3. 动态扩展实例的事件类型

如果希望实例化后能动态添加新事件名,可修改on方法的类型断言,自动扩展当前实例的事件类型:

class NamedHandler<T extends string = never> {
  handlers: Record<T, (...args: any[]) => void> = {} as Record<T, (...args: any[]) => void>;

  // 用asserts语法扩展实例的事件类型
  on<K extends string>(event: K, handler: (...args: any[]) => void): asserts this is NamedHandler<T | K> {
    (this.handlers as Record<T | K, (...args: any[]) => void>)[event] = handler;
  }

  emit(event: T, ...args: any[]) {
    this.handlers[event]?.(...args);
  }
}

const handler = new NamedHandler<'foo'>();
handler.on('bar', () => {}); // 调用后,handler的事件类型自动扩展为'foo'|'bar'
handler.emit('bar'); // ✅ 合法
说明

方案1适合固定扩展事件的场景,方案2适合需要灵活指定扩展事件的场景,方案3适合实例化后动态添加事件的场景,可根据实际需求选择。

内容的提问来源于stack exchange,提问作者Ingo Fischer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:59:57