在扩展 EventEmitter 的 TypeScript 类中声明事件
Posted
技术标签:
【中文标题】在扩展 EventEmitter 的 TypeScript 类中声明事件【英文标题】:Declaring events in a TypeScript class which extends EventEmitter 【发布时间】:2017-01-01 17:49:44 【问题描述】:我有一个扩展EventEmitter
的类,它可以发出事件hello
。如何使用特定的事件名称和侦听器签名声明 on
方法?
class MyClass extends events.EventEmitter
emitHello(name: string): void
this.emit('hello', name);
// compile error on below line
on(event: 'hello', listener: (name: string) => void): this;
【问题讨论】:
错误是什么?并且您的on
方法似乎缺少主体。
正如@NitzanTomer 所说,您的on
方法缺少主体,或者您想将event
参数声明为'hello'
以外的其他类型。
This answer 应该可以帮到你。
【参考方案1】:
最有用的方法是使用declare
:
declare interface MyClass
on(event: 'hello', listener: (name: string) => void): this;
on(event: string, listener: Function): this;
class MyClass extends events.EventEmitter
emitHello(name: string): void
this.emit('hello', name);
请注意,如果您要导出您的类,接口和类都必须使用export
关键字声明。
【讨论】:
只需让 Update 1 成为答案,因为另一种方式更成问题。【参考方案2】:这是我能够弄清楚的。用泛型覆盖默认函数!
interface IEmissions
connect: () => void
test: (property: string) => void
class MyClass extends events.EventEmitter
private _untypedOn = this.on
private _untypedEmit = this.emit
public on = <K extends keyof IEmissions>(event: K, listener: IEmissions[K]): this => this._untypedOn(event, listener)
public emit = <K extends keyof IEmissions>(event: K, ...args: Parameters<IEmissions[K]>): boolean => this._untypedEmit(event, ...args)
this.emit('test', 'Testing') // This will be typed for you!
// Example:
const inst = new MyClass()
inst.on('test', info => console.log(info)) // This will be typed!
【讨论】:
这正是我所需要的。这提供了在仍然强制输入的同时覆盖函数的能力。 非常优雅!我什至通过简单地调用super
不必将原始方法存储为成员来简化这一点。这在 TS 4.1.3 中对我有用:public on<K extends keyof MyEvents>(e: K, listener: MyEvents[K]): this return super.on(e, listener);
【参考方案3】:
您可以为此使用typed event emitter package。
例如:
import EventEmitter from 'tsee';
const events = new EventEmitter<
foo: (a: number, b: string) => void,
>();
// foo's arguments is fully type checked
events.emit('foo', 123, 'hello world');
这个包还提供接口和一些实用程序。
【讨论】:
这太棒了,我喜欢你的包!【参考方案4】:为了扩展@SergeyK 的答案,您可以在不重复事件类型的情况下对emit
和on
函数进行类型检查和完成。
-
为每种事件类型定义事件侦听器签名:
interface MyClassEvents
'add': (el: string, wasNew: boolean) => void;
'delete': (changedCount: number) => void;
-
根据 EventListeners (
MyClassEvents
) 函数签名声明构造 MyClass
类型的接口:
declare interface MyClass
on<U extends keyof MyClassEvents>(
event: U, listener: MyClassEvents[U]
): this;
emit<U extends keyof MyClassEvents>(
event: U, ...args: Parameters<MyClassEvents[U]>
): boolean;
-
只需定义扩展
EventEmitter
的类:
class MyClass extends EventEmitter
constructor()
super();
现在您将对on
和emit
函数进行类型检查:
不幸的是,您只能对这两个函数进行补全和类型检查(除非您在 MyClass 接口中定义了更多函数)。
要获得更通用的解决方案,您可以使用this package。 注意:它不会增加运行时开销。
import TypedEmitter from 'tiny-typed-emitter';
interface MyClassEvents
'add': (el: string, wasNew: boolean) => void;
'delete': (changedCount: number) => void;
class MyClass extends TypedEmitter<MyClassEvents>
constructor()
super();
【讨论】:
那个包真是太棒了。 到目前为止迄今为止我见过的最用户友好的解决方案。谢谢! @MaxTruxa 很高兴你发现它很有用:)【参考方案5】:将the official typing package 用于events library:
npm install events @types/events
【讨论】:
这是一个不同的包以上是关于在扩展 EventEmitter 的 TypeScript 类中声明事件的主要内容,如果未能解决你的问题,请参考以下文章
node node是什么 Buffer 模块化开发 第三方模块 事件订阅机制EventEmitter