Dependency Injection
WP-Node makes extensive use of dependency injection through TypeScript decorators.
It features a custom @component
decorator that enables automatic injection of dependencies into classes. This mechanism streamlines the resolution of services (e.g. Logger
, Meta
, and QueryUtil
classes), while also supporting lifecycle scoping for managed components.
What is @component
?β
@component
is a custom decorator provided by WP-Node Core. It marks a class as injectable and allows its dependencies to be automatically instantiated and passed into the constructor.
Example Usageβ
The following example demonstrates usage of the @component decorator with Transient scope:
// Mark this class as a component that can be resolved.
// 'Transient' scope means a new instance will be created every time it is requested.
@component({ scope: Scope.Transient })
export class Post {
constructor(
// These dependencies are automatically injected by the container
// as long as the class (e.g., Meta) is registered with the @component decorator.
public meta: Meta,
private logger: Logger,
private queryUtil: QueryUtil,
private postId: number
) {
// Example of setting up meta component with the current post ID
this.meta.set("post", postId);
}
async init() {
// queryUtil is already instantiated and injected β ready to use
const post = await this.queryUtil.posts((q) => q.get(this.postId));
if (!post) {
// logger is also already instantiated and injected- ready to use
this.logger.info(`Post not found: ${this.postId}`);
}
return post;
}
}
Supported Scopesβ
The decorator accepts a scope option, which determines the lifecycle of the injected instance:
Scope | Description |
---|---|
Singleton | A single instance shared across the entire application runtime. |
Context | A new instance created per logical context (e.g., per HTTP request). |
Transient | A new instance created each time the class is instantiated (no reuse). |
This design allows flexible control over object reuse and memory efficiency.
Using Components
to dynamically instantiate Componentβ
Components class plays a central role in WP-Nodeβs dependency injection system. While many components are injected directly into constructors, you can also inject Components container itself β giving you the flexibility to instantiate other components dynamically when needed.
This is especially useful when:
- You only need a component in specific methods (not in the constructor).
- You want lazy instantiation (create the instance only when itβs actually used).
get()
methodβ
Components.get
method allows you to manually instantiate any component that has been registered with @component decorator.
Example usageβ
@component({ scope: Scope.Transient })
export class Example {
constructor(private components: Components) {}
async getPostById(id: number): Promise<types.Tables["posts"]> {
// Dynamically resolve and instantiate PostUtil component.
const postUtil = this.components.get(PostUtil);
const post = await postUtil.get(id);
return post.props;
}
}
In this example:
- PostUtil component is not injected directly into the constructor.
- Instead, it is retrieved on-demand using components.get(PostUtil).
This approach keeps your component lean and only loads whatβs necessary for the current operation.