DEV Community

Cover image for The Poor Man's Dependency Injection for TypeScript: An Alternative Approach with Injectable Base Class
Ernesto Herrera Salinas
Ernesto Herrera Salinas

Posted on

The Poor Man's Dependency Injection for TypeScript: An Alternative Approach with Injectable Base Class

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;
}
Enter fullscreen mode Exit fullscreen mode

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";
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Benefits of Poor Man's Dependency Injection with an Injectable Base Class

  1. Simplicity: PMDI with an Injectable base class is easy to implement and understand, with no need to learn complex DI frameworks or libraries.
  2. Flexibility: Components can be easily replaced or mocked for testing, as they depend on interfaces rather than concrete implementations.
  3. 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)