@inweb/eventemitter2
Version:
JavaScript event emitter
155 lines (136 loc) • 5.34 kB
text/typescript
///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
// This application incorporates Open Design Alliance software pursuant to a
// license agreement with Open Design Alliance.
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
// All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////
/**
* The event interface for {@link IEventEmitter}.
*/
export interface IEvent {
/**
* Event type.
*/
type: string;
}
/**
* Event emitter interface.
*/
export interface IEventEmitter {
/**
* Registers a new listener for the event type.
*
* @param type - The type of event to listen to.
* @param listener - The function that gets called when the event is fired.
*/
addEventListener(type: string, listener: (event: IEvent) => void): this;
/**
* Removes the listener for the event type.
*
* @param type - The type of the event that gets removed.
* @param listener - The listener function that gets removed.
*/
removeEventListener(type: string, listener: (event: IEvent) => void): this;
/**
* If `type` is specified, removes all registered listeners for type, otherwise removes all registered
* listeners.
*
* @param type - The type of the listener that gets removed.
*/
removeAllListeners(type?: string): this;
/**
* Fires the event. Calls each of the listeners registered for the event type `event.type`, in the
* order they were registered.
*
* @param event - The event that gets fired.
*/
emitEvent(event: IEvent): boolean;
// Node.js style, to emit custom eventsg
/**
* Registers a new listener for the event type. Alias to {@link addEventListener | addEventListener()}
*
* @param type - The type of event to listen to.
* @param listener - The function that gets called when the event is fired.
*/
on(type: string, listener: (event: any) => void): this;
/**
* Removes the listener from an event type. Alias to
* {@link removeEventListener | removeEventListener()}.
*
* @param type - The type of the event that gets removed.
* @param listener - The listener function that gets removed.
*/
off(type: string, listener: (event: any) => void): this;
/**
* Fires the event. Alias to {@link emitEvent | emitEvent()}.
*
* @param type - The type of event that gets fired.
* @param args - The event properties.
*/
emit(type: string | object, ...args: any[]): boolean;
}
/**
* The minimal basic event that can be emitted by a {@link EventEmitter2}.
*/
export interface Event<T extends string = string> extends IEvent {
/**
* Event type.
*/
type: T;
}
/**
* Event emitter for custom objects.
*/
export class EventEmitter2<EventMap extends Record<string, any> = Record<string, any>> implements IEventEmitter {
private _listeners: Record<any, any[]> = {};
addEventListener<T extends keyof EventMap>(type: T, listener: (event: EventMap[T]) => void): this {
if (this._listeners[type] === undefined) this._listeners[type] = [];
this._listeners[type].push(listener);
return this;
}
removeEventListener<T extends keyof EventMap>(type: T, listener: (event: EventMap[T]) => void): this {
if (this._listeners[type] === undefined) return this;
const listeners = this._listeners[type].filter((x: any) => x !== listener);
if (listeners.length !== 0) this._listeners[type] = listeners;
else delete this._listeners[type];
return this;
}
removeAllListeners<T extends keyof EventMap>(type?: T): this {
if (type) delete this._listeners[type];
else this._listeners = {};
return this;
}
emitEvent<T extends keyof EventMap>(event: Event<Extract<T, string>> & EventMap[T]): boolean {
if (this._listeners[event.type] === undefined) return false;
const invoke = this._listeners[event.type].slice();
invoke.forEach((listener: any) => listener.call(this, event));
return true;
}
on(type: string, listener: (event: any) => void): this {
return this.addEventListener(type as any, listener as any);
}
off(type: string, listener: (event: any) => void): this {
return this.removeEventListener(type as any, listener as any);
}
emit(type: string | object, ...args: any[]): boolean {
if (typeof type === "string") return this.emitEvent({ type, args } as any);
else if (typeof type === "object") return this.emitEvent(type as any);
else return false;
}
}