API reference

EventEmitter

9/9Coverage8/9Strict (zero caveats)

Node's classic EventEmitter, imported from events (it is no global), not the WHATWG EventTarget/Event trio. With no type argument every event takes any arguments, @types/node's default event map; a type argument is an event map of argument tuples. The on/once/emit/off surface is compiled by the compiler rather than a registered class, so instanceof answers as a compile-time constant, and every listener is held as a dynamic function. A subclass can still override any of those methods (the override wins at every call site, and super.<method>(...) reaches the built-in).

Exact Works, with caveats Not supported

new EventEmitter<T>() / class X extends EventEmitter<T>

Works, with caveats
import { EventEmitter } from 'events'; new EventEmitter<T>(); class X extends EventEmitter<T> {}

Either construct a standalone emitter or root a class in one via extends — the subclass then gets the whole on/once/emit/off/removeListener/removeAllListeners/listenerCount/eventNames surface for free, and its constructor calls super(). With no T every event takes any arguments; T is an event map of argument tuples (`{ data: [chunk: string]; end: [] }`).

Returns

EventEmitter<T> — An emitter, or a subclass instance rooted in one.

import { EventEmitter } from 'events';
class Downloader extends EventEmitter {
  progress(chunk: number): void {
    this.emit("progress", this.name + ": " + this.bytesDone + " bytes");
  }
}
const bus = new EventEmitter();
See it in a full example →
⚠ Differences from standard
  • A subclass may override any EventEmitter method (on/once/emit/off/removeListener/removeAllListeners/listenerCount/eventNames) — the override wins at every call site (statically and virtually), and super.<method>(...) reaches the nearest ancestor override or the built-in dispatch. The override's declared signature isn't checked against the built-in it replaces
  • The type checker treats every event as taking any arguments; a typed map's event names and argument types are checked by code generation instead
  • Constructor options (captureRejections) are rejected

.on(event, listener) / .once(event, listener)

Exact
.on(event: string, listener: (...args) => void): this; .once(event, listener): this

Registers a listener for an event; once fires at most once then detaches itself. Both are chainable, returning the emitter. A listener may take fewer parameters than the event passes: one it isn't passed is undefined or its default.

Parameters
eventstring
Event name (a string literal for a map-typed emitter).
listener(...args) => void
Callback whose params match the event's payload type.
Returns

this — The emitter, for chaining.

dl.on("progress", (msg: string): void => {
  console.log(msg);
});
dl.once("complete", (name: string): void => {
  console.log("done: " + name);
});
See it in a full example →
⚠ Differences from standard
  • A **tuple** payload [A, B, …] is Node's multi-argument event — the listener takes one parameter per element ((a, b) => …); a non-tuple payload is a single argument (or none, for void). No open-ended (...args) beyond a declared tuple
  • A map-typed emitter requires a string-literal event name at every call site

.emit(event, ...args)

Exact
.emit(event: string, ...args): boolean

Synchronously invokes every listener registered for event, in registration order, with the emitter as this, passing along the arguments. Returns whether any listener ran.

Parameters
eventstring
Event name (a string literal for a map-typed emitter).
args...
The event's arguments.
Returns

boolean — true if at least one listener ran.

this.emit("progress", 512, 1024);
this.emit("done", "/tmp/file.bin");
See it in a full example →
⚠ Differences from standard
  • A map-typed emitter requires a string-literal event name

.off / .removeListener / .removeAllListeners

Exact
.off(event, listener): this; .removeListener(event, listener): this; .removeAllListeners(event?): this

Detaches listeners. off and removeListener remove the most recently added matching listener, keeping the rest in order. removeAllListeners with no argument clears every event; passed an event name, it clears just that one.

Parameters
eventstring
Event name; omitted on removeAllListeners to clear all.
listener(...args) => void
The exact listener reference to remove.
Returns

this — The emitter, for chaining.

bus.on("tick", onTick);
bus.off("tick", onTick);
bus.emit("tick", 2);   // (no listener left — no output)
See it in a full example →

.addListener / .prependListener / .prependOnceListener

Exact
.addListener(event, listener): this; .prependListener(event, listener): this; .prependOnceListener(event, listener): this

addListener is on under its other name. prependListener adds the listener before the ones already registered, so it runs first; prependOnceListener does the same for a one-shot listener.

Parameters
eventstring
Event name.
listener(...args) => void
The function to call.
Returns

this — The emitter, for chaining.

bus.on("tick", () => console.log("second"));
bus.prependListener("tick", () => console.log("first"));
bus.emit("tick");
⚠ Differences from standard
  • A map-typed emitter requires a string-literal event name

.listenerCount(event) / .eventNames()

Exact
.listenerCount(event: string | symbol): number; .eventNames(): (string | symbol)[]

listenerCount reports how many listeners are registered for an event. eventNames returns the names that currently have listeners, string names in registration order and then symbol names; an event whose last listener is removed drops out.

Parameters
eventstring | symbol
Event name to count (listenerCount only).
Returns

number | (string | symbol)[] — The listener count, or the array of event names.

console.log(bus.listenerCount("tick")); // 0
console.log(dl.listenerCount("progress")); // 1
See it in a full example →

emit('error', ...) special-case

Exact
.emit('error', payload): boolean // throws if no 'error' listener

Matches Node's one specially treated event name: emitting 'error' with no registered 'error' listener throws — the argument itself when it is an Error, otherwise an Error reading "Unhandled error. (<value>)", the value rendered by util.inspect.

Returns

boolean — As emit — but throws when 'error' has no listener.

try {
  dl.emit("error", "disk full");
} catch (e) {
  console.log("caught: " + e.message); // caught: Unhandled error. ('disk full')
}
See it in a full example →
⚠ Differences from standard
  • A non-Error, non-string argument is rendered with String() in the message, where Node uses util.inspect

events.once()

Exact
once(emitter: EventEmitter, name: string): Promise<args[]>

Returns a Promise that resolves with the event's argument array the first time it fires; an 'error' first rejects it, and an AbortSignal option cancels it.

Parameters
emitterEventEmitter
The emitter to observe.
namestring
The event name.
Returns

Promise<args[]> — Resolves with the event's arguments.

import { EventEmitter, once } from 'events'
const ee = new EventEmitter<{ ready: [number] }>()
setTimeout(() => { ee.emit('ready', 42) }, 0)
const arr = await once(ee, 'ready') // [42]
⚠ Differences from standard
  • Single-value / homogeneous multi-arg events only (mixed-type tuples rejected)

events.on()

Exact
on(emitter: EventEmitter, name: string): AsyncIterableIterator<args[]>

An async iterator yielding each emission's argument array (for await (const [x] of on(ee, 'data'))), buffering events between iterations; leaving the loop removes its listeners.

Parameters
emitterEventEmitter
The emitter to observe.
namestring
Callback taking the event's arguments.
Returns

AsyncIterableIterator<args[]> — An async iterator yielding each emission's argument array.

import { EventEmitter, on } from 'events'
const ee = new EventEmitter<{ tick: [number] }>()
setTimeout(() => { ee.emit('tick', 1); ee.emit('tick', 2) }, 0)
for await (const [n] of on(ee, 'tick')) {
  console.log(n)
  if (n >= 2) break
}
⚠ Differences from standard
  • A map-typed emitter requires a string-literal event name at every call site