ale*_*ung 13 node.js typescript
我有一个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;
}
Run Code Online (Sandbox Code Playgroud)
use*_*569 31
扩展@SergeyK 的答案,这样您就可以在不重复事件类型的情况下对两者emit
和on
函数进行类型检查和完成。
interface MyClassEvents {
'add': (el: string, wasNew: boolean) => void;
'delete': (changedCount: number) => void;
}
Run Code Online (Sandbox Code Playgroud)
MyClass
,基于 EventListeners( MyClassEvents
) 函数签名: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;
}
Run Code Online (Sandbox Code Playgroud)
EventEmitter
:class MyClass extends EventEmitter {
constructor() {
super();
}
}
Run Code Online (Sandbox Code Playgroud)
现在您将获得类型检查on
和emit
功能:
不幸的是,您只能对这两个函数进行补全和类型检查(除非您在 MyClass 接口中定义更多函数)。
要获得更通用的解决方案,您可以使用这个包。 注意:它不会增加运行时开销。
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();
}
}
Run Code Online (Sandbox Code Playgroud)
Ser*_*eyK 30
如果你想查看特定事件名称的类型,据我所知你只能使用这样的界面:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
有了这样的声明,当你使用类型的变量declare
时,在输入export
函数时会有一个类型的智能感知建议
更新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);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
这是我能够弄清楚的。用泛型覆盖默认函数!
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!
Run Code Online (Sandbox Code Playgroud)
您可以为此使用类型化事件发射器包。
例如:
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');
Run Code Online (Sandbox Code Playgroud)
这个包还提供了接口和一些实用程序。
小智 5
我真的很喜欢@Binier的答案,尤其是tiny-typed-emitter提供的通用解决方案。作为替代方案,我编写了这个纯打字稿版本:
type EmittedEvents = Record<string | symbol, (...args: any) => any>;
export declare interface TypedEventEmitter<Events extends EmittedEvents> {
on<E extends keyof Events>(
event: E, listener: Events[E]
): this;
emit<E extends keyof Events>(
event: E, ...args: Parameters<Events[E]>
): boolean;
}
export class TypedEventEmitter<Events extends EmittedEvents> extends EventEmitter {}
Run Code Online (Sandbox Code Playgroud)
它的使用方式类似:
type MessageSocketEvents = {
'message': (json: object) => void;
'close': () => void;
};
export class MessageSocket extends TypedEventEmitter<MessageSocketEvents> {
...
}
Run Code Online (Sandbox Code Playgroud)