TypeScript: EventEmitter子类事件的专用签名

8

我有一个基类 EventEmitter,其中有on方法来绑定特定事件的处理程序:

class EventEmitter {
    on(event: string, handler: Function) {
        /* add handler internally */
    }

    protected emit(event: string, ...args) {
        /* call all handlers listening on event */
    }
}

现在我有各种各样的子类,可以发出具有不同参数的不同事件。我想“声明”该特定类可以发出哪些事件:

class MyClass extends EventEmitter {
    on(event: 'event1', handler: (arg1: number) => void): void;
    on(event: 'event2', handler: (arg1: string, arg2: number) => void): void;
}

所以,我的子类可能会发出事件event1event2,但这似乎不是正确的指定方式。TypeScript(tsc 1.8)抱怨:

error TS2415: Class 'MyClass' incorrectly extends base class 'EventEmitter'.
  Types of property 'on' are incompatible.
Type '(event: "event1", handler: (arg1: number) => void) => void' is not assignable to type '(event: string, handler: Function) => void'.
  Type '(event: "event1", handler: (arg1: number) => void) => void' provides no match for the signature '(event: string, handler: Function): void'
error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
error TS2391: Function implementation is missing or not immediately following the declaration.

那么,指定我的类可以发出的事件的预期方式是什么?

编辑:我找到了我要找的东西的名称:专门签名。然而,它似乎只适用于接口,而不适用于新的TypeScript代码。

现在我找到了另一个问题,关于同样的问题,来自2015年,然而那里的解决方案看起来不太对。那么,今天在TypeScript中还有其他方法可以做到吗?


这个答案应该会对你有所帮助:链接 - aleclarson
1个回答

2
“指定我的类可以发出哪些事件的意图方式是什么?”相对于使用包含所有类型的单个事件流,更容易为每种类型分别使用一个独立的事件流,这是一个概念,称为“TypedEvent”。一个使用它的示例项目是http://alm.tools/。实现方法:https://github.com/alm-tools/alm/blob/55a8eb0f8ee411a506572abce92085235658b980/src/common/events.ts#L20-L72
这是一个使用示例:https://github.com/alm-tools/alm/blob/55a8eb0f8ee411a506572abce92085235658b980/src/server/lang/errorsCache.ts#L10
export let errorsUpdated = new TypedEvent<ErrorsUpdate>();
// emit: 
errorsUpdated.emit({} /* this will be type checked */);
// consume:
errorsUpdated.on((x)=>null); // x has the correct inferred type

这可能是一种方法,但它似乎是一种不同的风格。我想要采用现有的 node.js 风格 (instance.on(eventName, handler)) 和 HTML DOM 风格 (element.addEventListener(eventName, handler))。 - Simon
标准的node.js风格并不考虑静态类型检查。它依赖于文档而不是代码时间分析,并且在typescript中建模效果不佳。 - basarat
你能用我的示例类和事件展示一下你的方法吗?如果我理解正确,我应该为每个可能的事件定义一个事件子类。我的模块不是外部的,我的类共享相同的命名空间。两个类可能会发出“event1”/“Event1Event”,但具体取决于发出它的类的属性不同。 - Simon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接