Introduction
Dependency Injection (DI) is a software design pattern that allows developers to manage dependencies between components, making code more modular, testable, and maintainable. While various DI frameworks and libraries exist for TypeScript, such as InversifyJS or NestJS, you might want a simple, lightweight approach to dependency management without introducing external dependencies. In this article, we present an alternative Poor Man's Dependency Injection for TypeScript that utilizes an Injectable base class to manage dependencies.
What is Poor Man's Dependency Injection with an Injectable Base Class?
The Poor Man's Dependency Injection (PMDI) with an Injectable base class is a simplified method for implementing DI in TypeScript without relying on external libraries or frameworks. This approach leverages TypeScript's core features, such as classes, interfaces, and inheritance, to achieve dependency management. It offers an easy way for developers to understand and maintain the codebase without the overhead and complexity of full-featured DI frameworks.
Implementing Poor Man's Dependency Injection with an Injectable Base Class in TypeScript
Let's go through the steps to implement PMDI with an Injectable base class in a TypeScript project:
1. Define interfaces for your components
Interfaces are a fundamental aspect of TypeScript that enables you to define a contract for the structure and behavior of an object. By defining interfaces for your components, you can ensure they adhere to a specific API and can be replaced easily.
interface ILogger {
log(message: string): void;
}
interface IDataService {
fetchData(): string;
}
2. Implement the components
Next, implement the components using classes that conform to the previously defined interfaces. Each class should have a single responsibility and communicate with other components via their interfaces.
class ConsoleLogger implements ILogger {
log(message: string): void {
console.log(message);
}
}
class DataService implements IDataService {
fetchData(): string {
return "data from the server";
}
}
3. Create the Injectable base class
The Injectable base class will store the instances of dependencies as public static properties. This class can be extended by other classes that require these dependencies.
class Injectable {
public static logger: ILogger;
public static dataService: IDataService;
}
4. Extend the Injectable base class in the BusinessLogic
class
Instead of injecting dependencies through the constructor, we will extend the Injectable
base class in the BusinessLogic
class. This will provide access to the dependencies defined in the base class.
class BusinessLogic extends Injectable {
execute(): void {
BusinessLogic.logger.log("Executing business logic");
const data = BusinessLogic.dataService.fetchData();
BusinessLogic.logger.log(`Fetched data: ${data}`);
}
}
5. Initialize and wire up the components
Finally, create instances of the components and wire them together by setting the instances of the dependencies in the Injectable
class.
Injectable.logger = new ConsoleLogger();
Injectable.dataService = new DataService();
const businessLogic = new BusinessLogic();
businessLogic.execute();
Benefits of Poor Man's Dependency Injection with an Injectable Base Class
- Simplicity: PMDI with an Injectable base class is easy to implement and understand, with no need to learn complex DI frameworks or libraries.
- Flexibility: Components can be easily replaced or mocked for testing, as they depend on interfaces rather than concrete implementations.
- Maintainability: Decoupling components via interfaces and an Injectable base class promotes clean, modular code that is easier to maintain and refactor.
Conclusion
The Poor Man's Dependency Injection for TypeScript with an Injectable base class offers an alternative, simplified approach to dependency management, making it an excellent choice for smaller projects or those seeking a lightweight solution. Although it lacks some advanced features of full-fledged DI frameworks, PMDI with an Injectable base class provides enough flexibility and maintainability to help you build scalable and testable TypeScript applications. By extending the Injectable base class and managing dependencies as public static properties, you can achieve decoupling and separation of concerns in your TypeScript projects without the complexity of more advanced DI techniques.
Top comments (0)