@homer0/events-hub
Version:
A simple implementation of a pubsub service for handling events
124 lines (122 loc) • 5.6 kB
TypeScript
type GenericFn = (...args: any[]) => any;
type GenericParams = Parameters<GenericFn>;
type OnceWrapperFn = GenericFn & {
once: boolean;
};
/**
* When the service receives a "once subscription", it needs to track the listener so it
* gets removed after being called once, and to avoid modifying the original function, it
* creates a wrapper function that has the "once" property set to true. The wrapper and
* the original function are stored in case `off` is called before the wrapper gets
* triggered; it will receive the original function, not the wrapper, so the class needs a
* way to map them together.
*/
type OnceWrapper = {
/**
* A simple wrapper for the original listener, with the difference that it has a `once`
* property set to `true`.
*/
wrapper: OnceWrapperFn;
/**
* The original listener that will be called once.
*/
original: GenericFn;
};
/**
* A minimal implementation of an events handler service.
*/
declare class EventsHub {
/**
* A dictionary of the events and their listeners.
*/
protected events: Record<string, GenericFn[]>;
/**
* A dictionary of wrappers that were created for "one time subscriptions". This is
* used by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it
* will look for a wrapper and remove it.
*/
protected onceWrappers: Record<string, OnceWrapper[]>;
/**
* Gets all the listeners for a specific event.
* The list is returned by reference, so it can be modified once obtained.
*
* @param event The name of the event.
*/
protected getSubscribers(event: string): (GenericFn | OnceWrapperFn)[];
on<ListenerFn extends GenericFn = GenericFn>(event: string, listener: ListenerFn): () => boolean;
on<ListenerFn extends GenericFn = GenericFn>(event: string[], listener: ListenerFn): () => boolean[];
on<ListenerFn extends GenericFn = GenericFn>(event: string | string[], listener: ListenerFn): () => boolean | boolean[];
once<ListenerFn extends GenericFn = GenericFn>(event: string, listener: ListenerFn): () => boolean;
once<ListenerFn extends GenericFn = GenericFn>(event: string[], listener: ListenerFn): () => boolean[];
once<ListenerFn extends GenericFn = GenericFn>(event: string | string[], listener: ListenerFn): () => boolean | boolean[];
off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(event: string[], listener: ListenerFn): boolean[];
off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(event: string, listener: ListenerFn): boolean;
off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(event: string | string[], listener: ListenerFn): boolean | boolean[];
/**
* Emits an event and call all its listeners.
*
* @param event An event name or a list of them.
* @param args A list of parameters to send to the listeners.
* @template Args The type of the parameters to send to the listeners.
* @example
*
* const events = new EventsHub();
* events.on('event', (arg0) => {
* console.log(`Event received: ${arg0}`);
* });
* events.emit('event', 'Hello'); // prints "Event received: Hello"
*
*/
emit<Args extends GenericParams>(event: string | string[], ...args: Args): void;
/**
* Asynchronously reduces a target using an event. It's like emit, but the events
* listener return a modified (or not) version of the `target`.
*
* @param event An event name or a list of them.
* @param target The variable to reduce with the reducers/listeners.
* @param args A list of parameters to send to the reducers/listeners.
* @returns A version of the `target` processed by the listeners.
* @template Target The type of the target.
* @template Args The type of the parameters to send to the reducers/listeners.
* @example
*
* const events = new EventsHub();
* events.on('event', async (target, arg0) => {
* const data = await fetch(`https://api.example.com/${arg0}`);
* target.push(data);
* return target;
* });
* const result = await events.reduce('event', [], 'Hello');
* // result would be a list of data fetched from the API.
*
*/
reduce<Target, Args extends GenericParams>(event: string | string[], target: Target, ...args: Args): Promise<Target>;
/**
* Synchronously reduces a target using an event. It's like emit, but the events
* listener return a modified (or not) version of the `target`.
*
* @param event An event name or a list of them.
* @param target The variable to reduce with the reducers/listeners.
* @param args A list of parameters to send to the reducers/listeners.
* @returns A version of the `target` processed by the listeners.
* @template Target The type of the target.
* @template Args The type of the parameters to send to the reducers/listeners.
* @example
*
* const events = new EventsHub();
* events.on('event', (target, arg0) => {
* target.push(arg0);
* return target;
* });
* events.reduce('event', [], 'Hello'); // returns ['Hello']
*
*/
reduceSync<Target, ReducerArgs extends GenericParams>(event: string | string[], target: Target, ...args: ReducerArgs): Target;
}
/**
* Shorthand for `new EventsHub()`.
*
* @returns A new instance of {@link EventsHub}.
*/
declare const eventsHub: () => EventsHub;
export { EventsHub, eventsHub };