Skip to content

Providers

A provider is a recipe: a token to register under, and a way to produce the value. container.register accepts:

FormSpellingProduced
ClassApiClientconstructed on first resolve
Class with options{ useClass: ApiClient, ... }constructed on first resolve
Class, explicit token{ provide, useClass }constructed on first resolve
Value{ provide, useValue }never - you hand the value over
Factory{ provide, useFactory }the factory runs on first resolve
Alias{ provide, useExisting }never - points at another token
tsx
container.register([
    ApiClient,
    { useClass: OrdersCache, scope: "transient" },
    { provide: OrdersApi, useClass: RestOrdersApi },
    { provide: API_URL, useValue: "https://api.acme.dev" },
    { provide: CLOCK, useFactory: () => () => new Date() },
    { provide: OrdersReader, useExisting: OrdersApi },
])

There is no lazy here. The kernel constructs on first resolve anyway; eager construction is the module layer's init pass.

Options

  • provide - the token. Required on every object form except { useClass }, which registers under the class itself.
  • scope - on class and factory forms. A value is always a singleton; an alias has nothing to scope.
  • multi - contribute to a collection under the token instead of claiming it.
  • metadata - a frozen readonly bag carried to the entry's snapshot and events. The container never reads it.
ScopeInstances
singleton (default)one per container that declares it; cached after first resolve
transienta fresh one per resolve
requestone per resolution graph - shared by everything reached from a single resolve, gone when it returns

Tokens

A token is a class, a string, or a symbol. A class is its own token - that is the shorthand. For everything else, mint one:

tsx
import { makeTokenizer } from "@remodulo/container"

const token = makeTokenizer("@acme/orders")

export const API_URL = token<string>("api-url")

Every token is interned as Symbol.for("<namespace>:<name>") - the same name through the same namespace is always the same token, in any copy of the code sharing a process. Use your package name as the namespace.

Collections

A token is either single or multi, across the whole container chain. A single registration claims the token - a second claim throws. multi: true contributes - mixing the two throws at registration. resolve on a multi token throws; resolveAll on a single one throws.

A multi class provider needs an explicit provide.

Aliases

useExisting is a second name for an existing binding - it builds nothing, both names hand back the same instance.

  • An alias may be a member of a collection; it may never target one.
  • A dangling alias - target registered nowhere - throws from resolve, naming the target. resolveOptional and resolveOr treat it as a miss.
  • Each hop resolves from the container that declared the alias, so shadowing reads as usual.

MIT licensed.