Add general off handling
This commit is contained in:
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user