@Component

Register Classes With the Container

The @Component decorator marks a class for dependency injection. Every service, repository, controller, or runtime collaborator that the container should manage needs this decorator.

Basic Usage

Apply @Component({ scope: LoadAs.Singleton }) to stateless services, repositories, formatters, readers, and orchestration classes. The explicit scope matters because the decorator's library default is transient — always say what you mean.

user_service.ts
import { Component, Inject, LoadAs } from "@noego/ioc";
import { UserRepository } from "../repositories/user_repository";

@Component({ scope: LoadAs.Singleton })
export class UserService {
  constructor(
    @Inject(UserRepository) private users: UserRepository,
  ) {}

  async findDisplayName(userId: string): Promise<string> {
    const user = await this.users.findById(userId);
    return user?.displayName ?? "Unknown user";
  }
}

Swappable Contracts With Abstract Classes

Use abstract classes for injectable contracts. Interfaces disappear at runtime, so they cannot be container tokens. An abstract class serves as the token that both the consumer and the implementation reference.

email_sender.ts
import { Component, Inject, LoadAs } from "@noego/ioc";

export abstract class EmailSender {
  abstract send(to: string, body: string): Promise<void>;
}

@Component({ scope: LoadAs.Singleton })
export class SmtpEmailSender extends EmailSender {
  async send(to: string, body: string): Promise<void> {
    // Send through SMTP.
  }
}

@Component({ scope: LoadAs.Singleton })
export class InviteService {
  constructor(
    @Inject(EmailSender) private email: EmailSender,
  ) {}

  async invite(email: string): Promise<void> {
    await this.email.send(email, "Welcome to the workspace.");
  }
}

Rules

  • Use @Component on every class the container should manage.
  • Always specify an explicit scope — the default is transient.
  • Prefer LoadAs.Singleton for stateless services, repositories, formatters, and readers.
  • Use abstract classes (not interfaces) for swappable contracts — interfaces disappear at runtime.
  • Name decorator parameters explicitly; avoid relying on reflected metadata alone.
NoEgo

© 2025 NoEgo. All rights reserved.