typectx v0.8: A ProductSupplier Type You Can Actually Use
Version 0.8 rewrites typectx's internals so that the ProductSupplier type is finally practical for explicit type annotations. If you've ever wanted to annotate your suppliers to speed up TypeScript's language server in a large codebase, v0.7's generic signatures made that painful. v0.8 fixes the foundation.
Let's dive in.
The Problem: ProductSupplier Was Unusable for Annotations
In v0.7.1, ProductSupplier carried a giant generic signature inherited from the monolithic implementation. The defaults were wrong, the internal metadata was nested under a _ namespace, and the type parameters didn't have sensible enough defaults for you to write a simple annotation without specifying everything.
This matters because in large codebases, TypeScript's language server spends significant time re-inferring supplier types across files. The standard fix is explicit annotations—but if the annotation type itself is hostile, nobody will use it.
// v0.7.1 - The old ProductSupplier had too many required parameters
// and nested internal types that leaked into the signature
type ProductSupplier<
NAME, CONSTRAINT, SUPPLIERS, OPTIONALS, ASSEMBLERS,
HIRED, TEAM, DEPS, RESOLVED, CTX
> = { ... }
// Trying to annotate? Good luck.
const $myService: ProductSupplier<...ten params...> = market.add("myService").product({ ... })
The Fix: Cleaner Generics, Better Defaults
v0.8 restructures the type model around three clearer primitives:
BaseSupplier— shared shape for all suppliersRequestSupplier— for request-scoped dataProductSupplier— for factory-produced values
ProductSupplier now has sensible defaults for most parameters:
// v0.8 - ProductSupplier with defaults
interface ProductSupplier<
NAME extends string,
CONSTRAINT,
SUPPLIERS extends MainSupplier[] = [],
OPTIONALS extends RequestSupplier[] = [],
ASSEMBLERS extends UnknownProductSupplier[] = [],
HIRED extends UnknownProductSupplier[] = [],
KNOWN extends Record<string, unknown> = Record<never, unknown>,
MOCK extends boolean = boolean,
COMPOSITE extends boolean = boolean
> { ... }
Most of the time, you only need to specify NAME, CONSTRAINT, SUPPLIERS, OPTIONALS and ASSEMBLERS, which you can just copy-paste from your implementation. All the other params are inferred from those 5.
Internal Shape Cleanup: _ Namespace Removed
v0.7.1 tucked internal metadata under a _ namespace:
// v0.7.1
supplier._.product // true
supplier._.mock // false
supply._.ctx // the ctx function
supply._.packed // boolean
v0.8 flattens these to top-level fields:
// v0.8
supplier._product // true
supplier._request // false
supplier._mock // false
supply._ctx // the ctx function
supply._packed // boolean
This is a breaking change if you touched internals directly, but it removes an entire layer of indirection from both the runtime and the type system.
| v0.7.1 | v0.8 |
|---|---|
supplier._.product | supplier._product |
supplier._.mock | supplier._mock |
supply._.ctx | supply._ctx |
supply._.packed | supply._packed |
Modular Runtime
To make all of this maintainable, the monolithic implementation from v0.7.1 was split into focused modules:
| Module | Purpose |
|---|---|
src/product/main.ts | Core supplier construction and team building |
src/product/assemble.ts | The assemble() method |
src/product/build.ts | Internal _build(), Ctx(), reassemble() |
src/product/hire.ts | The hire() method |
src/product/mock.ts | The mock() method |
src/request.ts | Request supplier factory |
The public API (market.add().request() / .product()) is unchanged. This is purely an internal restructure.
Migration Guide
Step 1: Update internal field access (if applicable)
// Before
supplier._.product
supply._.ctx
// After
supplier._product
supply._ctx
Step 2: Update type imports (if using them)
// Before - v0.7.1 types
import type { Supply, ProductSupplier, Ctx, Deps, Resolved } from "typectx"
// These still exist, but their generic signatures have changed.
// After - v0.8 types (same names, cleaner generics)
import type { Supply, ProductSupplier, Ctx, Deps, Resolved } from "typectx"
Why These Changes?
- Practical annotations:
ProductSupplieris now usable as an explicit type, which is the single biggest lever for TS server performance in large codebases - Cleaner internals: Flattened
_namespace reduces type complexity and runtime indirection - Maintainable core: Modular runtime makes future changes safer
These are breaking changes for anyone touching internals or types directly, but for most app-level code, the migration is minimal.
npm install typectx@latest @typectx/react@latest