You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
2.5 KiB
84 lines
2.5 KiB
import { EventEmitter } from "events"; |
|
|
|
type TEventName = string | symbol; |
|
|
|
type AnyListener = (...args: any[]) => void; |
|
|
|
type Arguments<TListener> = TListener extends (...args: infer TArgs) => any |
|
? TArgs |
|
: any[]; |
|
type Listener<TEvents, TEvent extends keyof TEvents> = TEvents[TEvent] extends ( |
|
...args: infer TArgs |
|
) => any |
|
? (...args: TArgs) => void |
|
: AnyListener; |
|
|
|
export interface DefaultEvents { |
|
newListener: (event: TEventName, listener: AnyListener) => void; |
|
removeListener: (event: TEventName, listener: AnyListener) => void; |
|
} |
|
|
|
export type AnyEvents = DefaultEvents & { [event in TEventName]: any[] }; |
|
|
|
type IEventSubscriber<TEvents extends DefaultEvents, This> = < |
|
TEvent extends keyof TEvents & TEventName |
|
>( |
|
event: TEvent, |
|
listener: Listener<TEvents, TEvent> |
|
) => This; |
|
|
|
// tslint:disable:ban-types |
|
|
|
interface ITypedEventEmitter<TEvents extends DefaultEvents = AnyEvents> { |
|
on: IEventSubscriber<TEvents, this>; |
|
off: IEventSubscriber<TEvents, this>; |
|
once: IEventSubscriber<TEvents, this>; |
|
addListener: IEventSubscriber<TEvents, this>; |
|
removeListener: IEventSubscriber<TEvents, this>; |
|
prependListener: IEventSubscriber<TEvents, this>; |
|
prependOnceListener: IEventSubscriber<TEvents, this>; |
|
|
|
emit<TEvent extends keyof TEvents & TEventName>( |
|
event: TEvent, |
|
...args: Arguments<TEvents[TEvent]> |
|
): boolean; |
|
listeners<TEvent extends keyof TEvents & TEventName>( |
|
event: TEvent |
|
): Function[]; |
|
rawListeners<TEvent extends keyof TEvents & TEventName>( |
|
event: TEvent |
|
): Function[]; |
|
eventNames(): Array<keyof TEvents | TEventName>; |
|
setMaxListeners(maxListeners: number): this; |
|
getMaxListeners(): number; |
|
listenerCount<TEvent extends keyof TEvents & TEventName>( |
|
event: TEvent |
|
): number; |
|
} |
|
|
|
const TypedEventEmitter = EventEmitter as { |
|
new <TEvents extends DefaultEvents = AnyEvents>(): TypedEventEmitter<TEvents>; |
|
}; |
|
type TypedEventEmitter< |
|
TEvents extends DefaultEvents = AnyEvents |
|
> = ITypedEventEmitter<TEvents>; |
|
|
|
type Constructable = new (...args: any[]) => any; |
|
|
|
export function typedEventEmitter< |
|
TBase extends Constructable, |
|
TEvents extends DefaultEvents = AnyEvents |
|
>(Base: TBase): TBase & TypedEventEmitter<TEvents> { |
|
const NewClass = class extends Base { |
|
constructor(...args: any[]) { |
|
super(...args); |
|
EventEmitter.call(this as any); |
|
} |
|
}; |
|
Object.getOwnPropertyNames(EventEmitter.prototype).forEach(name => { |
|
NewClass.prototype[name] = (EventEmitter.prototype as any)[name]; |
|
}); |
|
return NewClass as any; |
|
} |
|
|
|
export { TypedEventEmitter };
|
|
|