TypeScript icon, indicating that this package has built-in type declarations

0.6.1Β β€’Β PublicΒ β€’Β Published


GitHub issues Travis

A ridiculously powerful and easy-to-use event system. πŸš€

How it works

The core: EventEmitter

This class can emit strongly-typed events. It's meant for use in any class, just add an event field with the emitter in it.

Here's an example:

interface ITestEvents {
	sayHello(name: string): any;
	sayGoodbye(name: string): any;

const emitter = new EventEmitter<any, ITestEvents>({});

emitter.emit("sayHello", "David"); // Success! We emitted the "sayHello" event with the correct parameters
emitter.emit("sayHello", 1); // Type error! We expect a name here, not a number

emitter.subscribe("sayHello", (_, name) => {
	console.log("Hello", name);

emitter.emit("sayHello", "Susan"); // logs "Hello Susan"

emit returns an array of the results from all calls.

Emitters always have a "host", which is the class they're in. Here's an example of using EventEmitter.Host as a superclass, and some inheritance:

interface ITestEvents {
	sayHello(name: string): any;

class Test extends EventEmitter.Host<ITestEvents> {}

const test = new Test();
test.event.emit("sayHello", "Johnny"); // `Test` extends `EventEmitter.Host`, which has a field `event: EventEmitter`

interface ITest2Events extends ITestEvents {
	sayGoodbye(name: string): any;

class Test2 extends Test {
	public readonly event: EventEmitter<this, ITest2Events>; // override with an emitter of additional events

const test2 = new Test2();
test2.event.emit("sayHello", "Kevin");
test2.event.emit("sayGoodbye", "Rachel");

There's more stuff you can do with a basic EventEmitter but, as per all open source projects, I'll save writing full docs for later~

Managing events project-wide: Excevent

The Excevent class is for setting up events project-wide, using "event buses".

An event bus allows subscribers to subscribe to potentially multiple different emitters of the same type. The emitters can also seamlessly change over time.


It's important that your file setting up excevent does not import actual classes, as this can cause circular dependencies and potentially issues. The excevent setup file should only declare the EventBus enum (or whatever else you decide to use for your event bus names), and the type of each event bus.

import type Foo from "./Foo";
import type Bar from "./Bar";

export enum EventBus {

export interface IEventBuses {
	[EventBus.Foo]: typeof Foo; // EventBus.Foo should include all events from all instances of the Foo class
	[EventBus.Bar]: Bar; // EventBus.Bar should include all events from the single registered instance of the Bar class

export const events = new Excevent<IEventBuses>();
export const EventHandler = excevent.getEventHandlerDecorator();

And then elsewhere, you register the classes or instances to the event bus. As an example:

import { events, EventBus } from "./Events";

interface IFooEvents {
	foo(): any;

export default class Foo extends EventEmitter.Host<IFooEvents> {}

events.registerBus(EventBus.Foo, Foo); // registers the Foo class to its event bus

Or, in the case of an instance:

import { events, EventBus } from "./Events";

interface IBarEvents {
	bar(): any;

export default class Bar extends EventEmitter.Host<IBarEvents> {
	public static readonly INSTANCE = new Bar();

events.registerBus(EventBus.Bar, Bar.INSTANCE); // registers a single instance of the Bar class to its event bus

Subscribing methods to events: @EventHandler





Package Sidebar


npm i @wayward/excevent

Weekly Downloads






Unpacked Size

63.5 kB

Total Files


Last publish


  • spacetech326
  • chirivulpes
  • drathy