Skip to content

Instantly share code, notes, and snippets.

@colxi
Created November 3, 2022 15:58
Show Gist options
  • Save colxi/a635b2fa8b1ddd9b21566e5bada56661 to your computer and use it in GitHub Desktop.
Save colxi/a635b2fa8b1ddd9b21566e5bada56661 to your computer and use it in GitHub Desktop.
export type EventsDictionary = Record<
string,
(event: CustomEvent<any>) => void
>
// Polyfill of CustomEvent for Node Environments
export class CustomEvent<T> extends Event {
constructor(type: string, detail: { detail: T }) {
super(type)
this.detail = detail.detail
}
public readonly detail: T
}
export default class EventedService<
E_DICTIONARY extends EventsDictionary = EventsDictionary
> {
constructor() {
this.#subscribers = {}
}
/**
* Collection of active subscribers grouped by event name
*/
readonly #subscribers: Record<
PropertyKey, Set<E_DICTIONARY[keyof E_DICTIONARY]>
>
/**
*
* Get the collection of subscribers for an event.
* If collections does not yet exist will be created
*
*/
private getEventSubscribersCollection<
E_NAME extends keyof E_DICTIONARY
>(eventName: E_NAME) : Set{
if (!this.#subscribers[eventName]){
this.#subscribers[eventName] = new Set()
}
return this.#subscribers[eventName]
}
/**
* Iterates the list of subscribers and executes the callback
* for a given event name
*/
protected dispatchEvent<E_NAME extends keyof E_DICTIONARY>(
...[eventName, eventData]: Parameters<E_DICTIONARY[E_NAME]>[0] extends void
? [E_NAME]
: [E_NAME, Parameters<E_DICTIONARY[E_NAME]>[0] extends CustomEvent<infer T> ? T : never]
) {
const eventHandlersCollection =
this.getEventSubscribersCollection(eventName)
const event = new CustomEvent(
String(eventName),
{ detail: eventData }
)
for (const eventHandler of eventHandlersCollection) {
eventHandler(event)
// stop Event Propagation if requested by user
if (event.cancelBubble) break
}
return event
}
/**
* Add the provided callback function to the list of subscribers for a given event name
*/
public subscribe<E_NAME extends keyof E_DICTIONARY, E_HANDLER extends E_DICTIONARY[E_NAME]>(
eventName: E_NAME,
eventHandler: E_HANDLER
): void {
const eventHandlersCollection = this.getEventSubscribersCollection(eventName)
eventHandlersCollection.add(eventHandler)
}
/**
* Remove the provided callback function to the list of subscribers for a given event name
*/
public unsubscribe<E_NAME extends keyof E_DICTIONARY, E_HANDLER extends E_DICTIONARY[E_NAME]>(
eventName: E_NAME,
eventHandler: E_HANDLER
): void {
const eventHandlersCollection = this.getEventSubscribersCollection(eventName)
eventHandlersCollection.delete(eventHandler)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment