Tiny, fully type-safe event emitter for Node, browser, and edge runtimes
npm install @philiprehberger/event-emitterTiny, fully type-safe event emitter for Node, browser, and edge runtimes
npm install @philiprehberger/event-emitter
import { createEmitter } from '@philiprehberger/event-emitter';
type Events = {
'user:login': { userId: string };
'user:logout': { userId: string; reason?: string };
'error': Error;
};
const emitter = createEmitter<Events>();
// Fully typed — event names and payloads are autocompleted
emitter.on('user:login', ({ userId }) => {
console.log(`User ${userId} logged in`);
});
// Listen once
emitter.once('user:login', ({ userId }) => { /* fires once */ });
// Manual unsubscribe
const off = emitter.on('error', (err) => console.error(err));
off(); // removes listener
// Or use off() directly
const handler = (data) => { /* ... */ };
emitter.on('user:logout', handler);
emitter.off('user:logout', handler);
const data = await emitter.waitFor('user:logout');
console.log(data.userId); // typed
emitter.onAny((event, data) => {
console.log(`Event: ${String(event)}`, data);
});
// One-time wildcard
emitter.onceAny((event, data) => {
console.log(`First event: ${String(event)}`, data);
});
emitter.eventNames(); // returns array of event names with active listeners
If a listener throws, remaining listeners still execute. Errors are collected and re-thrown as an AggregateError:
emitter.on('data', () => { throw new Error('fail'); });
emitter.on('data', (d) => console.log(d)); // still runs
try {
emitter.emit('data', payload);
} catch (e) {
// AggregateError with all listener errors
}
emitter.offAll('user:login'); // remove all listeners for one event
emitter.offAll(); // remove all listeners
emitter.listenerCount('error'); // number
const emitter = createEmitter<Events>({
maxListeners: 20, // warn if exceeded (default: 10)
});
createEmitter<E extends EventMap>(options?: EmitterOptions): Emitter<E>Creates a new type-safe emitter. E is a record mapping event names to their payload types
EmitterOptions| Property | Type | Default | Description |
|---|---|---|---|
maxListeners | number | 10 | Warn in console if exceeded. Set to 0 to disable. |
Emitter<E> Methods| Method | Signature | Description |
|---|---|---|
on | (event, listener) => () => void | Subscribe. Returns unsubscribe function. |
once | (event, listener) => () => void | Subscribe for one emission only. |
off | (event, listener) => void | Remove a specific listener. |
emit | (event, data) => void | Emit an event to all listeners. |
waitFor | (event) => Promise<data> | Returns a promise that resolves on next emission. |
onAny | (listener) => () => void | Listen to all events. Listener receives (event, data). |
offAll | (event?) => void | Remove all listeners for an event, or all listeners if no event given. |
listenerCount | (event) => number | Number of listeners for an event. |
onceAny | (listener) => () => void | Listen to all events once. Listener receives (event, data). |
eventNames | () => (keyof E)[] | Array of event names that have at least one listener. |
npm install
npm run build
npm test
If you find this project useful: