Skip to content

trananhtung/typemit

Repository files navigation

typemit

All Contributors

Tiny, fully type-safe event emitter — with a wildcard listener and a promise-based waitFor. Zero dependencies.

CI npm version bundle size types license

Most event emitters take (string, ...any[]) and hope for the best. typemit takes an event map, so the event name is checked, the payload type is inferred, and a typo or wrong payload is a compile error — not a 2 a.m. bug.

import { createEmitter } from "@billdaddy/typemit";

const bus = createEmitter<{
  login: { id: string };
  message: string;
  ready: void;
}>();

bus.on("login", (user) => console.log(user.id)); // user: { id: string }
bus.emit("login", { id: "42" });
bus.emit("ready");                                // void event — no payload
bus.emit("login", "oops");                        // ❌ compile error

Why typemit?

  • Type-safe end to end. on/once/emit/waitFor are all checked against your event map; void events take no payload.
  • waitFor as a promise. Await the next event — with an optional filter and an AbortSignal to bail out. Great for tests and request/response flows.
  • Wildcard listener. onAny((event, payload) => …) for logging/debugging.
  • Tidy lifecycle. on/once/onAny return an unsubscribe; clear() and listenerCount() for housekeeping. Handlers may unsubscribe themselves mid-emit.
  • Zero dependencies, ESM + CJS + types, ~1 kB.

Install

npm install @billdaddy/typemit
# or: pnpm add @billdaddy/typemit  /  yarn add @billdaddy/typemit  /  bun add @billdaddy/typemit

API

const bus = createEmitter<Events>();

Subscribe / emit

const off = bus.on("message", (text) => );  // returns unsubscribe
bus.once("ready", () => );                    // fires once
bus.off("message", handler);
bus.emit("message", "hello");
off();

waitFor(event, { signal?, filter? }) → Promise<payload>

const user = await bus.waitFor("login");
const big = await bus.waitFor("message", { filter: (m) => m.length > 100 });

const ac = new AbortController();
const next = bus.waitFor("login", { signal: ac.signal }); // rejects if aborted

Wildcard & housekeeping

const offAny = bus.onAny((event, payload) => log(event, payload));
bus.listenerCount("message"); // listeners for one event
bus.listenerCount();          // all listeners, incl. wildcard
bus.clear("message");         // remove one event's listeners
bus.clear();                  // remove everything

Pairs well with

  • timefence — race waitFor against a deadline.

Contributors ✨

This project follows the all-contributors specification. Contributions of any kind are welcome — code, docs, bug reports, ideas, reviews! See the emoji key for how each contribution is recognized, and open a PR or issue to get involved.

Thanks goes to these wonderful people:

Tung Tran
Tung Tran

💻 🚧

License

MIT © Tung Tran

About

Tiny, fully type-safe event emitter with a wildcard listener and a promise-based waitFor. Zero dependencies.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages