Runtime Values
Pass Request Data Into the Graph
Some classes need values that are only known at runtime: user IDs, tenant IDs, request IDs, roles, config strings, or feature flags. Use Parameter tokens for those values.
Defining a Parameter Token
Call Parameter.create("name") to create a token. The name is for debugging purposes — the actual token identity is the returned object reference.
export const USER_ID = Parameter.create("userId");
export const USER_ROLE = Parameter.create("userRole");Injecting a Parameter
Use @Inject(TOKEN) exactly like any other dependency. The parameter token is a first-class container citizen.
@Component({ scope: LoadAs.Scoped })
export class CurrentUser {
constructor(
@Inject(USER_ID) readonly userId: string,
@Inject(USER_ROLE) readonly role: "admin" | "member",
) {}
}Supplying Values at Resolution Time
Pass values when you call container.instance() using TOKEN.value(someValue). The container uses the value for that resolution and all of its transitive dependencies.
const reader = await requestScope.instance(PermissionReader, [
USER_ID.value("user-123"),
USER_ROLE.value("admin"),
]);Why Scoped Matters
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.
Rule of thumb: If a class consumes a Parameter whose value changes per request, make that class LoadAs.Scoped or LoadAs.Transient.
Full Example
Here is the complete pattern — token definition, injection, scoped container setup, and resolution — all together:
import createContainer, {
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"),
]);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.