useClass
Using useClass in Providers
The useClass option in a provider allows you to register a class as a dependency. When resolving the dependency, the container will instantiate and manage the class based on its lifecycle (singleton by default or transient if specified).
Example: Basic Usage
Here's how you can register a class using useClass:
import { ContainerResolver } from "depinjionary";
import { CalculatorService } from "./calculator.service";
const providers = [
  { provide: CalculatorService, useClass: CalculatorService }
];
const container = ContainerResolver.init(providers);
const calculator = await container.resolve<CalculatorService>(CalculatorService);
console.log(calculator.calculate(5, 10)); // Outputs: 15
Binding Classes to Interfaces
One of the most powerful uses of useClass is binding a class to an interface, allowing for better abstraction and flexibility. Here's an example:
Define an Interface
export interface LoggerInterface {
  debug(data: string): void;
  log(data: string): void;
}
export const LoggerInterface = Symbol('LoggerInterface');
Create a Class Implementation
export class ConsoleLoggerService implements LoggerInterface {
  debug(data: string): void {
    console.debug(`DEBUG: ${data}`);
  }
  log(data: string): void {
    console.log(`LOG: ${data}`);
  }
}
Register the Class to the Interface
const providers = [
  { provide: LoggerInterface, useClass: ConsoleLoggerService }
];
const container = ContainerResolver.init(providers);
// Resolving the interface token returns the implementation
const logger = await container.resolve<LoggerInterface>(LoggerInterface);
logger.log("This is a log message.");
Why Symbol Tokens?
By using Symbol tokens for interfaces (e.g., LoggerInterface), you ensure that the container can uniquely identify the dependency. It’s also convenient to export a Symbol with the same name as the interface due to TypeScript’s ability to differentiate between types and values.
Benefits of useClass
- Abstraction: Decouple implementation details from the interface, making your code more flexible and testable.
- Readability: Use descriptive tokens (like the interface name) to make dependencies clear.
- Convenience: The natural ability of TypeScript to export both the interface and the symbol under the same name makes it easier to manage dependencies.
Key Notes
- Use useClassfor cases where a class implements an interface or needs to be instantiated dynamically.
- Always prefer Symbolorstringtokens for interfaces to avoid naming conflicts.
- Resolve dependencies using container.resolve()for type-safe and intuitive access.