Resolution

Resolve Dependencies at the Right Moment

Most of the time, the container resolves everything for you automatically through constructor injection. But some scenarios need explicit resolution: passing runtime values that aren't known at startup, or selecting an implementation class based on request data.

Explicit Resolution at a Glance

This example shows both explicit resolution patterns — runtime parameters and scoped container selection — working together:

report_exporter.ts
import createContainer, {
  Component,
  Inject,
  LoadAs,
  Parameter,
  SCOPED_CONTAINER,
  type IContainer,
} from "@noego/ioc";

export const USER_ID = Parameter.create("userId");

@Component({ scope: LoadAs.Singleton })
export class ReportExporter {
  constructor(
    @Inject(SCOPED_CONTAINER) private container: IContainer,
  ) {}

  async export(userId: string): Promise<Buffer> {
    const scope = this.container.extend();
    const report = await scope.instance(ReportService, [
      USER_ID.value(userId),
    ]);
    return report.generate();
  }
}

Documentation

Core Rules

  • Most classes should resolve their dependencies through normal constructor injection — the container handles this automatically.
  • Use Parameter.create() for values only known at runtime (user IDs, feature flags, request IDs).
  • Use SCOPED_CONTAINER only when runtime data selects which implementation class to use.
  • Keep resolution code thin — business logic belongs in the resolved implementation, not in the resolution bridge.
  • Create a fresh child scope per request or page to isolate scoped instances.
NoEgo

© 2025 NoEgo. All rights reserved.