Dependency graphs, just typed functions.
@favy/di v3 turns ordinary TypeScript functions into named, composable dependency providers. Dependency objects stay explicit, results stay inferred, and concrete implementations are selected at the composition root—without decorators or container configuration.
- Build named modules from ordinary functions
- Carry transitive requirements through
Live<T> - Replace dependencies at the application boundary
- Bind known values incrementally with
.provide() - Resolve lazily and cache within each run by default
- Customize input and output types when a graph needs them
npm install @favy/diRequires TypeScript 5+.
import { Module, type Live } from '@favy/di';
const Clock = Module()('Clock', () => ({
now: () => new Date(),
}));
type ClockLive = Live<typeof Clock>;
const Greeting = Module<ClockLive>()('Greeting', ({ Clock }) => {
const hour = Clock.now().getUTCHours();
return hour < 12 ? 'Good morning!' : 'Good evening!';
});Modulecreates a named callable provider from a typed dependency object and an ordinary function.Live<T>carries a module's transitive requirements plus its result under the module's declared name.- The composition root is the top-level call where the application assembles concrete values and providers.
import { Module, type Live } from '@favy/di';
const Clock = Module()('Clock', () => ({
now: () => new Date(),
}));
type ClockLive = Live<typeof Clock>;
const Greeting = Module<ClockLive>()('Greeting', ({ Clock }) => {
const hour = Clock.now().getUTCHours();
return hour < 12 ? 'Good morning!' : 'Good evening!';
});
console.log(
Greeting({
Clock: { now: () => new Date('2025-01-01T09:00:00.000Z') },
}),
); // "Good morning!"The replacement is a plain value with the same contract as the value produced by Clock; no container mutation or special test API is required.
Use .provide() to bind part of a dependency object and get back a module that asks only for the remaining fields.
import { Module } from '@favy/di';
const Add = Module<{ left: number; right: number }>()(
'Add',
({ left, right }) => left + right,
);
const AddTen = Add.provide({ right: 10 });
console.log(AddTen({ left: 5 })); // 15| Default | Behavior |
|---|---|
lazy: true |
A supplied provider runs only when its key is first read. |
cache: 'run' |
Its resolved value is reused for the current top-level call; if its key is read in a later run, the provider resolves again. |
- Introduction
- Testing
- Caching
- Lazy initialization
- Partial application
- Input transforms
- Output transforms
- API reference
See the documentation contributor guide for local commands. Bug reports and pull requests are welcome in the GitHub repository.
@favy/di is distributed under the MIT license. See the LICENSE file.