Skip to content

Quick Start

Build the dependency graph through a fluent API. TypeScript matches each dependency tuple to the target constructor, so swapped and missing arguments fail at compile time. The wiring uses plain code, without @Injectable() decorators or reflect-metadata.

ts
import { Container } from '@inferdi/inferdi'

class Logger {
  log(message: string) {
    console.log(`[LOG] ${message}`)
  }
}

class UserRepo {
  constructor(
    private readonly logger: Logger,
    private readonly dsn: string,
  ) {}

  find(id: string) {
    this.logger.log(`Finding ${id} in ${this.dsn}`)
  }
}

const container = new Container()
  .registerValue('dsn', 'postgres://localhost/app')
  .registerClass('logger', Logger, [])
  .registerClass('userRepo', UserRepo, ['logger', 'dsn'])

container.get('userRepo').find('42')

The call to registerClass('userRepo', UserRepo, ['logger', 'dsn']) is checked positionally. If you swap the tuple to ['dsn', 'logger'], TypeScript reports the mismatch before the app runs.

Resolve Values

Use .get(key) for resolution:

ts
const repo = container.get('userRepo')

The key must be registered in the container type. Unknown static keys are compile errors. Dynamic keys should be probed with .has(key) before .get(key).

Choose Lifetimes

Registrations default to singleton. Pass the lifetime as the fourth argument for classes, or the third argument for factories.

ts
const root = new Container()
  .registerClass('logger', Logger, [])
  .registerClass('request', RequestContext, [], 'scoped')
  .registerClass('token', Token, [], 'transient')
KindCreatedCachedDisposed by container
singletononce per owning containeryesyes
scopedonce per scopeyesyes
transientevery resolvenono

Singletons cannot directly depend on scoped or transient services. That rule is enforced by types and, in strict mode, by runtime guards.