Parameters
Inject Runtime Values With Parameter.create()
Not every dependency is a class. Some values — user IDs, tenant IDs, request IDs, roles, config strings, feature flags — are only known at runtime. Use Parameter.create() to create injectable tokens for those values.
Defining and Injecting Parameters
Call Parameter.create("name") to produce a token. Inject it with @Inject(TOKEN) like any other dependency. Supply the value with TOKEN.value(someValue) at the resolution call site.
import { Component, Inject, LoadAs, Parameter } from "@noego/ioc";
export const USER_ID = Parameter.create("userId");
export const USER_ROLE = Parameter.create("userRole");
@Component({ scope: LoadAs.Scoped })
export class CurrentUser {
constructor(
@Inject(USER_ID) readonly userId: string,
@Inject(USER_ROLE) readonly role: "admin" | "member",
) {}
}
@Component({ scope: LoadAs.Scoped })
export class PermissionReader {
constructor(
@Inject(CurrentUser) private user: CurrentUser,
) {}
canEdit(): boolean {
return this.user.role === "admin";
}
}
const root = createContainer();
const requestScope = root.extend();
const reader = await requestScope.instance(PermissionReader, [
USER_ID.value("user-123"),
USER_ROLE.value("admin"),
]);Why Parameters Need Scoped State
A singleton is created once and reused. If a singleton consumes a runtime parameter, it can accidentally keep the first value it received. Request-specific values belong in scoped state so each request, page, or conversation gets its own instance.
Rules
- Create one Parameter token per runtime value.
- Parameter tokens are plain values — they don't need @Component.
- Pass parameter values at the top-level resolution call using .value().
- Keep parameter-consuming classes Scoped or Transient when values change per request.
- Do not use parameters for dependencies that should be normal injected services.