Dependency injection by type in TypeScript
Depend on an interface; the caller supplies whatever satisfies it.
interface Clock {
now(): number;
}
interface Store {
save(lang: string, tpm: number): Promise<void>;
}
interface Deps {
clock: Clock;
store: Store;
}
function makeRecorder({ clock, store }: Deps) {
return async function record(lang: string, tpm: number): Promise<string> {
await store.save(lang, tpm);
return `${lang} at ${tpm} (${clock.now()})`;
};
}
const calls: string[] = [];
const record = makeRecorder({
clock: { now: () => 1234 },
store: { save: async (lang, tpm) => void calls.push(`${lang}:${tpm}`) },
});
record("ts", 98).then((line) => console.log(line, calls));
How it works
- The interface is the contract, and it stays small.
- A test passes a fake with no framework involved.
- Partial application is enough: no container needed.
Keywords and builtins used here
ClockPromiseStoreasyncawaitconstfunctioninterfacenumberreturnstring
The run, in numbers
- Lines
- 27
- Characters to type
- 578
- Tokens
- 188
- Three-star pace
- 110 tpm
At the three-star pace of 110 tokens a minute, this run takes about 103 seconds.
Step 2 of 5 in Building & injecting, step 10 of 19 in Classes & patterns.