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:
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.