Universal, type-safe EventEmitter for Node.js and browser runtimes. Drop it into libraries or apps that expect Node’s API surface (on, off, once, emit) without pulling in the original polyfill.
- Type-driven event maps: every event name maps to a tuple of argument types for full IntelliSense.
- Zero dependencies, small footprint, and identical behavior across environments.
- Extras beyond Node’s core:
clearListenersandlistenerCountto manage teardown and diagnostics. - Ships as ESM, CJS, and IIFE bundles with generated
.d.tsfiles for TS consumers.
pnpm add @avensio/event-emitter
# npm install @avensio/event-emitter
# yarn add @avensio/event-emitterimport { EventEmitter } from '@avensio/event-emitter'
interface Events {
ready: [void]
data: [{ id: string }]
}
const emitter = new EventEmitter<Events>()
emitter.on('ready', () => console.log('ready'))
emitter.emit('data', { id: '42' })Use tuples for every event payload—even when there’s a single argument.
ready: [void]ensures handlers receive zero args, whiledata: [{ id: string }]enforces one object argument.
| Method | Signature | Notes |
|---|---|---|
on |
on(event, listener) |
Registers a listener and returns this for chaining. |
once |
once(event, listener) |
Listener auto-unsubscribes after the first emission. |
emit |
emit(event, ...args): boolean |
Synchronously calls listeners; returns false when none were registered. Exceptions bubble to the caller. |
off |
off(event, listener?) |
Remove a single listener or all listeners for the event when listener is omitted. |
clearListeners |
clearListeners(event?) |
Alias for off(event); with no arguments clears every event. Useful during teardown. |
listenerCount |
listenerCount(event?) |
Returns count for a specific event or totals all listeners when omitted. |
See the API reference for full signatures, overloads, and return values.
const emitter = new EventEmitter<{ change: [string, unknown], error: [Error] }>()
// Fire-and-forget state updates
emitter.emit('change', 'theme', 'dark')
// Once listeners
emitter.once('change', (key) => console.debug('first change', key))
// Teardown in frameworks
onUnmounted(() => emitter.clearListeners())
// Diagnostics
console.log('listeners:', emitter.listenerCount())More recipes (composition, bridging DOM events, wrapping async workflows) live in docs/usage.md.
| Command | Description |
|---|---|
pnpm test |
Run Vitest (test/emitter.test.ts) with coverage outputs in coverage/. |
pnpm lint |
ESLint (auto-fix) for src/. |
pnpm build |
Builds ESM, CJS, and IIFE bundles and regenerates declarations. |
pnpm docs:dev / docs:build |
Work on the VitePress docs. |
pnpm release |
test + build + changelog automation. |
Clone the repo, pnpm install, and keep docs/tests synced with API changes. See docs/development.md for the full workflow.