Dependency Injection in TypeScript: A Guide with InversifyJS

Dependency Injection in TypeScript: A Guide with InversifyJS
Aktualisiert am 13.6.2025
Tobias Bueck

Tobias Bueck

Hello! I am Tobias Bueck, founder of Softoft. As a computer scientist, I share insights on my blog about software development, particularly the OTOBO ticket system, as well as automation tools like UIPath and Zapier.

In this article, we explain how to implement Dependency Injection in TypeScript using the InversifyJS library. The goal is to elucidate the benefits of Dependency Injection and to demonstrate how to make your code more efficient and maintainable by using InversifyJS.

What is Dependency Injection in TypeScript?

Dependency Injection (DI) is a design pattern that reduces coupling between classes (Loose Coupling). It allows classes to communicate via interfaces or abstractions rather than directly interacting. DI increases the testability and flexibility of code. In TypeScript, InversifyJS offers a powerful library that simplifies this implementation.

Why Dependency Injection?

Without Dependency Injection, classes are often tightly bound to specific implementations. This complicates future changes and increases the potential for errors. DI solves this problem by managing dependencies centrally and providing them automatically.

Dependency Injection in TypeScript with a Weather Forecasting System

As an example, we will develop a small weather forecasting system with two different forecasters: "WeatherSatellite" and "WeatherStation". Both forecasters implement weather forecasting, but we want to design the system so that the specific forecasting method remains flexible.

Example without Dependency Injection

class WeatherSatellite {
    getTemperature(): number {
        return 20;
    }
}

class WeatherStation {
    getTemperature(): number {
        return 22;
    }
}

class Person {
    private weatherSatellite: WeatherSatellite;

    constructor() {
        this.weatherSatellite = new WeatherSatellite();
    }
}

UML Diagram: Current Design without Dependency Injection

UML Diagram: Example without Dependency Injection
UML Diagram: Example without Dependency Injection

Problem: The Person class decides which weather forecasting method to use. This leads to strong coupling and makes it difficult to change or extend the implementation.

Improvement: Introduction of Interfaces

In TypeScript, we can use interfaces to abstract dependencies. Here we define an IWeatherForecasting interface:

interface IWeatherForecasting {
    getTemperature(): number;
}

class WeatherSatellite implements IWeatherForecasting {
    getTemperature(): number {
        return 20;
    }
}

class WeatherStation implements IWeatherForecasting {
    getTemperature(): number {
        return 22;
    }
}

class Person {
    private weatherForecasting: IWeatherForecasting;

    constructor(weatherForecasting: IWeatherForecasting) {
        this.weatherForecasting = weatherForecasting;
    }
}

UML Diagram: Interface Implementation without Dependency Injection

UML Diagram: Interface
UML Diagram: Interface

Problem: Even though an interface is now used, the Person class still decides which implementation to use. This contradicts the DI principle.

Solution: Dependency Injection with InversifyJS

To fully resolve this dependency, we use InversifyJS to automatically inject the required objects.

Code Example: Using InversifyJS for Dependency Injection

First, we need to install InversifyJS and reflect-metadata:

npm install inversify reflect-metadata

Then create the TypeScript code with InversifyJS:

import 'reflect-metadata';
import {Container, injectable, inject} from 'inversify';

const TYPES = {
    IWeatherForecasting: Symbol.for('IWeatherForecasting')
};

interface IWeatherForecasting {
    getTemperature(): number;
}

@injectable()
class WeatherSatellite implements IWeatherForecasting {
    getTemperature(): number {
        return 20;
    }
}

@injectable()
class WeatherStation implements IWeatherForecasting {
    getTemperature(): number {
        return 22;
    }
}

@injectable()
class Person {
    private weatherForecasting: IWeatherForecasting;

    constructor(@inject(TYPES.IWeatherForecasting) weatherForecasting: IWeatherForecasting) {
        this.weatherForecasting = weatherForecasting;
    }

    getForecast(): number {
        return this.weatherForecasting.getTemperature();
    }
}

const container = new Container();
container.bind<IWeatherForecasting>(TYPES.IWeatherForecasting).to(WeatherSatellite);
const person = container.resolve(Person);

console.log(person.getForecast()); // Output: 20

Explanation

  • @injectable: Decorator that makes the class available for Dependency Injection.
  • @inject: Allows the injection of dependencies into the class constructor.
  • Container: Defines which implementations are used for the respective dependencies.

UML Diagram: Design with Dependency Injection

UML Diagram: Dependency Container
UML Diagram: Dependency Container

Advantage

The Person class is now completely independent of the weather forecasting implementation. Changes to the implementation can easily be made in the DI container.

Extending the DI Container

It is also possible to add other implementations or dependencies to the container by using different bindings with .to().

Frequently Asked Questions about Dependency Injection

Why should I use InversifyJS instead of manual Dependency Injection?

InversifyJS simplifies the management of dependencies and makes the code more modular. Manually managing dependencies can lead to errors and hard-to-maintain code, especially in larger applications.

Can InversifyJS also be used in frontend frameworks like Angular?

Yes, InversifyJS can be used both in the backend (Node.js) and in the frontend with frameworks like Angular or React. However, it is important to check whether the chosen DI approach can be well integrated into the respective framework.

Conclusion

Dependency Injection in TypeScript with the InversifyJS library helps to make code more modular, flexible, and maintainable. InversifyJS enables easy management of dependencies, making the code easier to adapt and extend.

CookieFirst Logo

Wir verwenden Cookies

Wir können diese zur Analyse unserer Besucherdaten platzieren, um unsere Webseite zu verbessern, personalisierte Inhalte anzuzeigen und Ihnen ein großartiges Webseiten-Erlebnis zu bieten. Für weitere Informationen zu den von uns verwendeten Cookies öffnen Sie die Einstellungen.