Add general off handling

This commit is contained in:
2026-08-07 02:11:40 +00:00
parent a948671251
commit 8b47dd2d8b
2 changed files with 23 additions and 1 deletions
+7 -1
View File
@@ -117,11 +117,17 @@ export class EventEmitter<T extends EventMap> {
* @param type - The event type. * @param type - The event type.
* @param listener - The listener function. * @param listener - The listener function.
*/ */
off<K extends keyof T>(type: K, listener: Listener<T[K]>): void { off<K extends keyof T>(type: K, listener?: Listener<T[K]>): void {
// Get the listeners for the event type. // Get the listeners for the event type.
const listeners = this.#listeners.get(type); const listeners = this.#listeners.get(type);
if (!listeners) return; if (!listeners) return;
// If no listener is provided, remove all listeners for the event type.
if (!listener) {
this.#listeners.delete(type);
return;
}
// Find the listener entry. // Find the listener entry.
const listenerEntry = Array.from(listeners).find((entry) => entry.listener === listener || entry.wrappedListener === listener); const listenerEntry = Array.from(listeners).find((entry) => entry.listener === listener || entry.wrappedListener === listener);
+16
View File
@@ -124,6 +124,21 @@ const testEventEmitterOffRemovesListenerByReference = (): void => {
expect(listener).not.toHaveBeenCalled(); expect(listener).not.toHaveBeenCalled();
}; };
/**
* Tests that off() removes all listeners for an event type when no listener is provided.
*/
const testEventEmitterOffRemovesAllListenersForEventType = (): void => {
const emitter = new EventEmitter<TestEvents>();
const listener = vi.fn();
emitter.on('message', listener);
emitter.off('message');
expect(listener).not.toHaveBeenCalled();
expect(emitter.emit('message', 'hello')).toBe(false);
expect(emitter.emit('count', 42)).toBe(false);
};
/** /**
* Tests that off() does nothing when given an unknown listener reference. * Tests that off() does nothing when given an unknown listener reference.
*/ */
@@ -484,6 +499,7 @@ const runTests = async (): Promise<void> => {
test('EventEmitter: returns true when emitting with listeners', testEventEmitterEmitReturnsTrueWithListeners); test('EventEmitter: returns true when emitting with listeners', testEventEmitterEmitReturnsTrueWithListeners);
test('EventEmitter: stops calling a listener after its off callback is invoked', testEventEmitterOffCallbackRemovesListener); test('EventEmitter: stops calling a listener after its off callback is invoked', testEventEmitterOffCallbackRemovesListener);
test('EventEmitter: removes a listener when off is called with the same reference', testEventEmitterOffRemovesListenerByReference); test('EventEmitter: removes a listener when off is called with the same reference', testEventEmitterOffRemovesListenerByReference);
test('EventEmitter: removes all listeners for an event type when off is called with no listener', testEventEmitterOffRemovesAllListenersForEventType);
test('EventEmitter: ignores off when the listener reference is unknown', testEventEmitterOffIgnoresUnknownListener); test('EventEmitter: ignores off when the listener reference is unknown', testEventEmitterOffIgnoresUnknownListener);
test('EventEmitter: ignores off for an event type with no listeners', testEventEmitterOffIgnoresUnregisteredEventType); test('EventEmitter: ignores off for an event type with no listeners', testEventEmitterOffIgnoresUnregisteredEventType);
test('EventEmitter: calls a once listener only one time', testEventEmitterOnceListenerFiresOnce); test('EventEmitter: calls a once listener only one time', testEventEmitterOnceListenerFiresOnce);