From 0fa9528a3ff7d688f5e418eac3aa42e6214bff32 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Thu, 18 May 2023 13:22:51 +0100 Subject: [PATCH] Comments for typed-event-emitter classes (#3380) * Comments for typed-event-emitter classes * Export `TypedEventEmitter` ... to stop tsdoc complaining. --- src/matrix.ts | 1 + src/models/typed-event-emitter.ts | 118 +++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/src/matrix.ts b/src/matrix.ts index a60376df6a4..2034665748b 100644 --- a/src/matrix.ts +++ b/src/matrix.ts @@ -37,6 +37,7 @@ export * from "./models/event-timeline-set"; export * from "./models/poll"; export * from "./models/room-member"; export * from "./models/room-state"; +export * from "./models/typed-event-emitter"; export * from "./models/user"; export * from "./models/device"; export * from "./scheduler"; diff --git a/src/models/typed-event-emitter.ts b/src/models/typed-event-emitter.ts index c359df5d18f..7eac48b962b 100644 --- a/src/models/typed-event-emitter.ts +++ b/src/models/typed-event-emitter.ts @@ -17,6 +17,7 @@ limitations under the License. // eslint-disable-next-line no-restricted-imports import { EventEmitter } from "events"; +/** Events emitted by EventEmitter itself */ export enum EventEmitterEvents { NewListener = "newListener", RemoveListener = "removeListener", @@ -24,10 +25,22 @@ export enum EventEmitterEvents { } type AnyListener = (...args: any) => any; + +/** Base class for types mapping from event name to the type of listeners to that event */ export type ListenerMap = { [eventName in E]: AnyListener }; + type EventEmitterEventListener = (eventName: string, listener: AnyListener) => void; type EventEmitterErrorListener = (error: Error) => void; +/** + * The expected type of a listener function for a particular event. + * + * Type parameters: + * * `E` - List of all events emitted by the `TypedEventEmitter`. Normally an enum type. + * * `A` - A type providing mappings from event names to listener types. + * * `T` - The name of the actual event that this listener is for. Normally one of the types in `E` or + * {@link EventEmitterEvents}. + */ export type Listener, T extends E | EventEmitterEvents> = T extends E ? A[T] : T extends EventEmitterEvents @@ -40,12 +53,20 @@ export type Listener, T extends E | E * This makes it much easier for us to distinguish between events, as we now need * to properly type this, so that our events are not stringly-based and prone * to silly typos. + * + * Type parameters: + * * `Events` - List of all events emitted by this `TypedEventEmitter`. Normally an enum type. + * * `Arguments` - A {@link ListenerMap} type providing mappings from event names to listener types. + * * `SuperclassArguments` - TODO: not really sure. Alternative listener mappings, I think? But only honoured for `.emit`? */ export class TypedEventEmitter< Events extends string, Arguments extends ListenerMap, SuperclassArguments extends ListenerMap = Arguments, > extends EventEmitter { + /** + * Alias for {@link TypedEventEmitter#on}. + */ public addListener( event: T, listener: Listener, @@ -53,32 +74,97 @@ export class TypedEventEmitter< return super.addListener(event, listener); } + /** + * Synchronously calls each of the listeners registered for the event named + * `event`, in the order they were registered, passing the supplied arguments + * to each. + * + * @param event - The name of the event to emit + * @param args - Arguments to pass to the listener + * @returns `true` if the event had listeners, `false` otherwise. + */ public emit(event: T, ...args: Parameters): boolean; public emit(event: T, ...args: Parameters): boolean; public emit(event: T, ...args: any[]): boolean { return super.emit(event, ...args); } + /** + * Returns the number of listeners listening to the event named `event`. + * + * @param event - The name of the event being listened for + */ public listenerCount(event: Events | EventEmitterEvents): number { return super.listenerCount(event); } - public listeners(event: Events | EventEmitterEvents): ReturnType { + /** + * Returns a copy of the array of listeners for the event named `event`. + */ + public listeners(event: Events | EventEmitterEvents): Function[] { return super.listeners(event); } + /** + * Alias for {@link TypedEventEmitter#removeListener} + */ public off(event: T, listener: Listener): this { return super.off(event, listener); } + /** + * Adds the `listener` function to the end of the listeners array for the + * event named `event`. + * + * No checks are made to see if the `listener` has already been added. Multiple calls + * passing the same combination of `event` and `listener` will result in the `listener` + * being added, and called, multiple times. + * + * By default, event listeners are invoked in the order they are added. The + * {@link TypedEventEmitter#prependListener} method can be used as an alternative to add the + * event listener to the beginning of the listeners array. + * + * @param event - The name of the event. + * @param listener - The callback function + * + * @returns a reference to the `EventEmitter`, so that calls can be chained. + */ public on(event: T, listener: Listener): this { return super.on(event, listener); } + /** + * Adds a **one-time** `listener` function for the event named `event`. The + * next time `event` is triggered, this listener is removed and then invoked. + * + * Returns a reference to the `EventEmitter`, so that calls can be chained. + * + * By default, event listeners are invoked in the order they are added. + * The {@link TypedEventEmitter#prependOnceListener} method can be used as an alternative to add the + * event listener to the beginning of the listeners array. + * + * @param event - The name of the event. + * @param listener - The callback function + * + * @returns a reference to the `EventEmitter`, so that calls can be chained. + */ public once(event: T, listener: Listener): this { return super.once(event, listener); } + /** + * Adds the `listener` function to the _beginning_ of the listeners array for the + * event named `event`. + * + * No checks are made to see if the `listener` has already been added. Multiple calls + * passing the same combination of `event` and `listener` will result in the `listener` + * being added, and called, multiple times. + * + * @param event - The name of the event. + * @param listener - The callback function + * + * @returns a reference to the `EventEmitter`, so that calls can be chained. + */ public prependListener( event: T, listener: Listener, @@ -86,6 +172,15 @@ export class TypedEventEmitter< return super.prependListener(event, listener); } + /** + * Adds a **one-time**`listener` function for the event named `event` to the _beginning_ of the listeners array. + * The next time `event` is triggered, this listener is removed, and then invoked. + * + * @param event - The name of the event. + * @param listener - The callback function + * + * @returns a reference to the `EventEmitter`, so that calls can be chained. + */ public prependOnceListener( event: T, listener: Listener, @@ -93,10 +188,25 @@ export class TypedEventEmitter< return super.prependOnceListener(event, listener); } + /** + * Removes all listeners, or those of the specified `event`. + * + * It is bad practice to remove listeners added elsewhere in the code, + * particularly when the `EventEmitter` instance was created by some other + * component or module (e.g. sockets or file streams). + * + * @param event - The name of the event. If undefined, all listeners everywhere are removed. + * @returns a reference to the `EventEmitter`, so that calls can be chained. + */ public removeAllListeners(event?: Events | EventEmitterEvents): this { return super.removeAllListeners(event); } + /** + * Removes the specified `listener` from the listener array for the event named `event`. + * + * @returns a reference to the `EventEmitter`, so that calls can be chained. + */ public removeListener( event: T, listener: Listener, @@ -104,7 +214,11 @@ export class TypedEventEmitter< return super.removeListener(event, listener); } - public rawListeners(event: Events | EventEmitterEvents): ReturnType { + /** + * Returns a copy of the array of listeners for the event named `eventName`, + * including any wrappers (such as those created by `.once()`). + */ + public rawListeners(event: Events | EventEmitterEvents): Function[] { return super.rawListeners(event); } }