Skip to content

Peer dependencies ​

sh
pnpm add @btravstack/di unthrown

unthrown is declared as a peer dependency, so installing di means installing both. This page is the reasoning.

The Result must be your Result ​

Every fallible operation in di returns an unthrown Result, and — the half that matters — your code continues those values: a make you write returns a Result that di's build pipeline flatMaps; the Result an entry point hands back is one your code matches. The values cross the package boundary in both directions, constantly.

Were unthrown a regular dependency, your application and di could resolve two copies of it — different major versions declared, or a package manager that deduplicates less aggressively than pnpm. Two copies means two Result identities. TypeScript's structural typing might forgive some of it; runtime behaviour will not: combinators from one copy receiving the other's values, instanceof-based narrowing quietly false, two TaggedError worlds whose pattern tags never match. The failure mode is not an error message — it is a match arm that silently never fires.

A peer dependency is the package-manager-level statement that rules this out: there is one unthrown in this application, owned by the application, and di links against it. Your lockfile pins its version once; di's declared range (^5.0.0) only constrains compatibility.

Why not zero dependencies instead ​

The alternative — di shipping its own internal result type, or throwing like everyone else — was rejected because the error channel is not an implementation detail here; it is half the design. E is a typed channel your make functions feed and your match sites consume, and defects need somewhere to go that is not your error union. Reinventing that inside di would give it a private dialect of the discipline the rest of a btravstack application (and entity, which makes the same choice for the same reason) already speaks. Sharing the vocabulary is the point; peering is how you share a vocabulary safely.

Why the examples install it themselves ​

Each example package declares unthrown in its own package.json even though di already requires it. That is the peer contract seen from the consumer's side: a peer is the consumer's dependency, not a transitive one, and with pnpm's strict linking an undeclared peer is simply not importable. Your application does the same — which is why the install line at the top of every guide names both packages.

Released under the MIT License.