Skip to content

Latest commit

 

History

History
100 lines (75 loc) · 2.86 KB

File metadata and controls

100 lines (75 loc) · 2.86 KB

MiniSignal

signals, in TypeScript, fast and safe

Basic Usage

import { MiniSignal } from 'mini-signals';

// Define a mini-signal
// The optional type argument specifies the listener parameter types
const mySignal = new MiniSignal<[string, string]>();

// Add a listener
// The listener parameter types must match the type argument specified in the MiniSignal constructor
// The returned binding can be used to remove the listener later
const binding = mySignal.add((foo: string, bar: string) => {
  console.log('signal dispatched');
  expect(foo).toBe('foo');
  expect(bar).toBe('bar');
});

// Dispatch the signal, passing parameters to the listeners
mySignal.dispatch('foo', 'bar');

// Remove the listener using the binding
mySignal.detach(binding);

Adding MiniSignal to Objects

const myObject = {
  foo: 'bar',
  updated: new MiniSignal<[]>(),
};

myObject.updated.add(() => {
  console.log('signal dispatched');
  expect(myObject.foo).toBe('baz');
});

myObject.foo = 'baz';
myObject.updated.dispatch(); // dispatch signal

Flavoring the signal

Flavoring (or branding) a signal ensures that only bindings created by that specific signal can be used to detach listeners from it. This prevents accidentally attempting to detach a binding from a different signal; which would result in a runtime error.

import { MiniSignal } from 'mini-signals';

const mySignal = new MiniSignal<[string, string], 'mySignal'>();
const myOtherSignal = new MiniSignal<[string, string], 'myOtherSignal'>();

const binding = mySignal.add((foo: string, bar: string) => {
  // ...
});

expect(() => {
  // @ts-ignore
  myOtherSignal.detach(binding);
}).toThrow(
  'MiniSignal#detach(): MiniSignal listener does not belong to this MiniSignal.'
);

Async Listeners

Listeners can return Promises to indicate asynchronous operations. The dispatchSerial and dispatchParallel methods will wait for these Promises to resolve before completing.

import { MiniSignal } from 'mini-signals';

// Define a mini-signal
// The optional type argument specifies the listener parameter types
const mySignal = new MiniSignal<[string, string]>();

// Add a listener
// The listener parameter types must match the type argument specified in the MiniSignal constructor
// The returned binding can be used to remove the listener later
const binding = mySignal.add(async (foo: string, bar: string) => {
  await doSomethingAsync();
  console.log('signal dispatched');
  expect(foo).toBe('foo');
  expect(bar).toBe('bar');
});

// Dispatch the signal, passing parameters to each listener in series
// Wait for all listeners to complete
await mySignal.dispatchSerial('foo', 'bar');

// Dispatch the signal, passing parameters to each listener in parallel
// Wait for all listeners to complete
await mySignal.dispatchParallel('foo', 'bar');

// Remove the listener using the binding
mySignal.detach(binding);