TSyringe: Lightweight Dependency Injection for TypeScript/JavaScript

TSyringe: Lightweight Dependency Injection for TypeScript/JavaScript

Summary

TSyringe is a lightweight dependency injection (DI) container developed by Microsoft for JavaScript and TypeScript applications. It provides a robust solution for managing class dependencies, making your codebase more modular, testable, and maintainable. By leveraging decorators, TSyringe simplifies the process of injecting dependencies into your classes, adhering to the Inversion of Control (IoC) principle.

Repository Info

Updated on February 12, 2026
View on GitHub

Tags

Click on any tag to explore related repositories

Introduction

TSyringe is a lightweight dependency injection (DI) container developed by Microsoft for JavaScript and TypeScript applications. It provides a robust solution for managing class dependencies, making your codebase more modular, testable, and maintainable. By leveraging decorators, TSyringe simplifies the process of injecting dependencies into your classes, adhering to the Inversion of Control (IoC) principle.

Installation

To get started with TSyringe, you need to install it via npm or yarn and configure your TypeScript project.

First, install the package:

npm install --save tsyringe
# or
yarn add tsyringe

Next, modify your tsconfig.json to enable experimental decorators and emit decorator metadata:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Finally, add a polyfill for the Reflect API, typically reflect-metadata, at the entry point of your application:

// main.ts
import "reflect-metadata";

// Your application code here...

Examples

TSyringe makes it straightforward to inject dependencies, especially when working with interfaces to promote loose coupling. Here's an example demonstrating dependency injection with interfaces:

// SuperService.ts
export interface SuperService {
  doSomething(): string;
}

// TestService.ts
import { SuperService } from "./SuperService";

export class TestService implements SuperService {
  doSomething(): string {
    return "Hello from TestService!";
  }
}

// Client.ts
import { injectable, inject } from "tsyringe";
import { SuperService } from "./SuperService";

@injectable()
export class Client {
  constructor(@inject("SuperService") private service: SuperService) {}

  execute(): string {
    return `Client executing: ${this.service.doSomething()}`;
  }
}

// main.ts
import "reflect-metadata";
import { container } from "tsyringe";
import { Client } from "./Client";
import { TestService } from "./TestService";

// Register the implementation for the 'SuperService' token
container.register("SuperService", {
  useClass: TestService
});

const client = container.resolve(Client);
console.log(client.execute()); // Output: Client executing: Hello from TestService!

Why Use TSyringe?

Adopting a dependency injection container like TSyringe offers several significant advantages for your projects:

  • Improved Testability: Dependencies can be easily mocked or swapped out during unit testing, simplifying the testing process.
  • Loose Coupling: Components are less dependent on concrete implementations, making your codebase more flexible and easier to refactor.
  • Enhanced Maintainability: Centralized management of dependencies reduces boilerplate code and makes it easier to understand and modify how components interact.
  • Scalability: Supports the development of larger, more complex applications by providing a structured way to manage dependencies across many modules.
  • Clearer Code Structure: Promotes a clean architecture and adherence to SOLID principles, leading to more organized and readable code.

Links

For more detailed information, documentation, and to contribute, visit the official TSyringe resources: