typed-emitter
Zero-runtime, strictly typed EventEmitter interface for TypeScript.
Repository Health
Technical Analysis
typed-emitter provides a single TypeScript interface, TypedEventEmitter<Events>, that you cast onto any existing event emitter (Node’s built-in events.EventEmitter or a compatible custom implementation) to get compile-time type checking of event names and listener argument types. It ships no runtime code at all — just .d.ts declaration files — so it adds zero bytes to your bundle while catching typos in event names and mismatched listener signatures that the default @types/node EventEmitter typings let through silently.
The built-in EventEmitter types accept any string as an event name and any function as a listener, so a typo like emit("mesage", ...) or a listener with the wrong argument types only fails at runtime, if at all. typed-emitter fixes this by parameterizing every method (on, once, emit, off, removeAllListeners, etc.) over a declared EventMap, so mismatches are caught by tsc before the code ships. It also ships an optional typed-emitter/rxjs submodule with a FromEvent type that restores the type inference RxJS’s fromEvent otherwise loses when used against a typed emitter.
What You Get
- A
TypedEventEmitter<Events>generic interface you cast onto any EventEmitter instance - Compile-time checking of event names against your declared
EventMap - Compile-time checking of listener argument types for
on,once,emit, and related methods - An
rxjssubmodule with aFromEventtype that fixesfromEvent’s lost type inference - Zero runtime code — pure
.d.tstypings with no bundle-size cost
Common Use Cases
- Wrapping Node’s
events.EventEmitterto get typed pub/sub for internal service or module events - Extending
EventEmitterin a custom class withTypedEmitter<T>generics to ship a typed public API - Adding type-safe events to socket, stream, or other custom emitter-shaped implementations
- Getting correctly typed RxJS
Observables out offromEventfor a typed emitter
Under The Hood
Architecture
typed-emitter has no runtime layer — its entire surface is a hand-written index.d.ts declaring one generic interface, TypedEventEmitter<Events extends EventMap>, whose methods (on, once, emit, off, removeAllListeners, listeners, eventNames, etc.) are all parameterized over keyof Events and Parameters<Events[E]> so each method call is checked against the caller-supplied event map. A second, optional module (rxjs/index.d.ts) extends that base interface with an __events marker field and declares a FromEvent type that intersects a hand-written overload with RxJS’s own fromEvent signature, restoring the Observable<T> inference that would otherwise degrade to unknown. Because the entire package is one composed generic type, any change to the EventMap/TypedEventEmitter shape would break every consumer relying on the cast pattern.
Tech Stack
The package has zero production dependencies; RxJS is only an optionalDependency/devDependency (^7.5.2) used solely by the optional rxjs submodule. There is no build step — package.json points main at an effectively empty types.js stub and types at the hand-authored index.d.ts, so the published package is the raw TypeScript declaration files with no transpilation or bundling involved.
Code Quality
No test files or test framework are present in the repository, so correctness is enforced entirely by TypeScript’s own type checker rather than by an automated test suite. There is no committed linter or formatter configuration, though an inline /* eslint-disable no-use-before-define */ comment in rxjs/index.d.ts implies ESLint is used in some external workflow. The declaration files themselves are internally consistent, narrowly scoped, and rely on precise generics (keyof, Parameters<>) rather than any, which is what the package’s whole value proposition depends on.
API Design
The package solves a specific, well-known gap: neither @types/node’s EventEmitter typings nor eventemitter3’s bundled types let you parameterize event names and listener argument types together. typed-emitter’s fix is a single, low-boilerplate cast — new EventEmitter() as TypedEmitter<Events> — that mirrors Node’s own EventEmitter method names exactly, so there’s no new API to learn and no wrapper class or runtime cost. The README documents the base cast, the class-extension pattern (including a generic-class variant), and the RxJS interop case with runnable snippets, though the project has had no commits since late 2022 and issues around type-inference edge cases (e.g. the linked fromEvent compatibility discussion) remain open.
Used by 4 apps in this directory
Huly Platform
Project Management · Team Chat · Collaboration
Open-source all-in-one workspace that replaces Linear, Jira, Slack, and Notion for product and engineering teams.
Mastra Code
AI Code Assistants
"A coding agent that never compacts" — a terminal-based AI coding agent built on the Mastra framework, with Observational Memory instead of context compaction, multi-model support, and OAuth login for Claude Max or ChatGPT Plus.
Notesnook
Note Taking · File Storage · Security
End-to-end encrypted, open-source note-taking where your data stays yours — even from the server.
Trigger.dev
Automation · AI Development · Developer Tools
Build and deploy fully-managed AI agents and background jobs in TypeScript — with no timeouts, durable retries, real-time observability, and elastic scaling built in.