composited
v3.0.0
Published
Dumb library for adding composition to JavaScript
Readme
composited
Dumb library for adding composition to JavaScript.
How usies?
// Creature.ts
export class Creature {
name: string;
constructor(name: string) {
this.name = name;
}
}// GreetableCreature.ts
import { Creature } from "./Creature.js";
import { composeCheck } from "composited";
export class GreetableCreature {
that: Creature;
constructor(that: any) { this.that = composeCheck(Creature, that); }
count = 0;
greet() {
console.log(`Hi! I'm ${this.that.name}. I was greeted ${++this.count} times!`);
}
}// index.ts
import { Creature } from "./Creature.js";
import { GreetableCreature } from "./GreetableCreature.js";
import { $ } from "composited";
const leah = new Creature("Léah");
leah[$](GreetableCreature).greet(); // Hi! I'm Léah. I was greeted 1 times!
leah[$](GreetableCreature).greet(); // Hi! I'm Léah. I was greeted 2 times!As of v2.x.y, you can also use composited with primitives.
How workies?
We extend Object.prototype with $, a symbol. (And since it's a symbol, it won't pollute anything).
We use a WeakMap to map each value with an inner WeakMap (or simply a Map for non-WeakKeys) mapping each ThatClass object to the class instance.
API
We assume: import { $ } from "composited";
Object#[$]: (ThatClass: new (v: any) => unknown) => InstanceType<typeof ThatClass>
Gets, or creates, the instance of the "trait" ThatClass. When creating, it will instanciate ThatClass with this (the object it's used on) as an argument.
composeCheck(InputClass: new (v: any) => unknown, v: any) => InstanceType<typeof InputClass>
Behaves as an identity function if v is an instance of InputClass . Will throw a CompositionError otherwise. Meant as a helper function to make trait creation faster.
CompositionError
Error specifying the impossibility to perform the composition.
More obsure and less useful API, might remove at my own discretion
CompositionsHandler.compositions: WeakMap<WeakKey, OnEmptyWeakMap<new (v: WeakKey) => unknown, unknown>>
The memoization WeakMap of all compositions from WeakKey, to WeakMaps from class objects (traits), to class instances
(OnEmptyWeakMap is a WeakMap with a FinalizationRegistry such that when the WeakMap is empty, a hook is called to remove it from e.g. the upper weakMap)
CompositionsHandler.compositions: WeakMap<StrongKey, OnEmptyWeakMap<new (v: WeakKey) => unknown, unknown>>
The memoization Map of all compositions from StrongKey, to WeakMaps from class objects (traits), to class instances
CompositionsHandler.get(ThatClass: new (v: WeakKey) => unknown, obj: WeakKey):
Creates or gets the trait defined by ThatClass holding a reference to obj. Requires obj be a WeakKey.
CompositionsHandler.getStrong(ThatClass: new (v: StrongKey) => unknown, obj: StrongKey)
Creates or gets the trait defined by ThatClass holding a reference to obj.
