strictly-typed-events
An Event emitting/subscription library designed for simplicity, convenience, and
type-safety in TypeScript projects.
Contents
Installation
Install via npm:
npm i -s strictly-typed-events
Why?
Despite the many event libraries already available on npm
, I could not find
one that met my desires. My goal is to easily setup a class that emits
well-defined events, with type-safety while emitting and subscribing/handling,
using minimal boilerplate. It should also be simple and intuitive to emit the
events, subscribe to events, and cancel subscriptions to events.
Some design goals:
- Simplicity of an "event" just being a call to a named handler function, with
the "payload" being represented as one or more function parameters.
- Define all events for a given class in terms of a single interface of event
handler function signatures.
- Support subscribing to multiple events with one call, which subsequently supports
cancelling that entire subscription to multiple events with one call.
- Easily support exposing only the means to subscribe to events, while keeping
the means to emit events private.
Example Usage/Patterns
Here's some basic usage examples of strictly-typed-events
and suggested patterns
to get you started. See documentation in the source code (detailed TSDoc/JSDoc
style comments on all types/classes/methods/etc.) for full details.
Subscribing and Cancelling Subscriptions
For the following examples, assume there is a variable source
that implements
this library's EventSource
interface (has the on()
/once()
/subscribe()
methods to subscribe to events).
Subscribe to one event at a time:
const cancel = source.on("nameChanged", (newname, oldName) => {
});
cancel();
Subscribe to one event with a one-time-only handler:
source.once("nameChanged", (newname, oldName) => {
});
Get a Promise that will be resolved the next time an event is emitted:
source.onceAsPromise("nameChanged").then(([newname, oldName]) => {
});
Or subscribe to multiple events at once:
const cancel = source.subscribe({
nameChanged: (newname, oldName) => {
},
anotherEvent: once((whatever) => {
}),
});
cancel();
Add Events via Inheritence
Here's the simplest, lowest-effort way to add events to a class.
This works well for simple situations where your class is not already
extending another class, and you want the on()
subscription
method to be directly on your class.
import { WithEventEmitter } from "strictly-typed-events";
class Foo extends WithEventEmitter<{
nameChanged(newName: string, oldName: string): void;
anotherEvent(whatever: number): void;
}> {
public constructor(private readonly name: string) {
super();
}
public setName(newName: string): void {
const oldName = this.name;
this.name = newName;
this.emit.nameChanged(newName, oldName);
}
}
const foo = new Foo();
const cancel = foo.on("nameChanged", (newname, oldName) => {
});
cancel();
Add Events via Composition
If you either don't want to, or are unable to, use inheritence to add
events to your class, then you can do it through composition instead.
This approach guarantees that you have no conflicts between properties/methods
on your class and WithEventEmitter
.
import { EventEmitter } from "strictly-typed-events";
class Foo {
private readonly emitter = new EventEmitter<{
nameChanged(newName: string, oldName: string): void;
anotherEvent(whatever: number): void;
}>();
public readonly events = this.emitter.toEventSource();
public constructor(private readonly name: string) {}
public setName(newName: string): void {
const oldName = this.name;
this.name = newName;
this.emitter.emit.nameChanged(newName, oldName);
}
}
const foo = new Foo();
const cancel = foo.events.on("nameChanged", (newname, oldName) => {
});
cancel();