TypeScript IoC Container

3.2.2 · active · verified Sun Apr 19

typescript-ioc is a lightweight, annotation-based dependency injection (DI) container specifically designed for TypeScript applications. It allows developers to manage dependencies using decorators like `@Inject`, simplifying object graph creation and promoting modular design. The library is currently stable at version 3.2.2, with the 3.x series being actively maintained through frequent patch and minor releases. Key differentiators include its small footprint, ease of use with TypeScript decorators, and broad environmental support including Node.js, browsers, and React Native. It provides features such as different scopes (Singleton, Request, Local), factory creation, and configuration capabilities, making it suitable for both simple and complex application architectures where inversion of control is desired. A notable change in the 3.x series was the discontinuation of support for ES5 runtimes, requiring modern JavaScript environments (ES6 or newer).

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates basic setup with `@Inject` for property and named value injection, `@Scope` for singleton management, and `Container.bind()` for interface-to-implementation mapping. Also shows manual resolution and direct instantiation.

import { Inject, Container, Scope } from "typescript-ioc";

// Ensure your tsconfig.json has:
// "experimentalDecorators": true,
// "emitDecoratorMetadata": true,
// "target": "es6"

interface ILogger {
  log(message: string): void;
}

@Scope(Scope.Singleton)
class ConsoleLogger implements ILogger {
  private readonly timestamp: Date;
  constructor() {
    this.timestamp = new Date();
    console.log(`ConsoleLogger instance created at ${this.timestamp.toISOString()}`);
  }
  log(message: string): void {
    console.log(`[${this.timestamp.toISOString()}] ${message}`);
  }
}

class DatabaseService {
  @Inject
  private logger!: ILogger; // '!' is TypeScript's definite assignment assertion

  connect(): void {
    this.logger.log("Attempting to connect to database...");
    // Simulate database connection logic
  }
}

class UserService {
  @Inject
  private dbService!: DatabaseService;

  @Inject('APP_NAME') // Injecting a constant value defined by Container.bindName
  private appName!: string;

  createUser(username: string): void {
    this.dbService.connect();
    console.log(`[${this.appName}] Creating user: ${username}`);
    // Simulate user creation logic
  }
}

// Configure the container: bind an interface to an implementation
Container.bind(ILogger).to(ConsoleLogger);
// Bind a named constant value
Container.bindName('APP_NAME').to('MyAwesomeApp');

// Option 1: Get instance from the container to ensure all dependencies are resolved
const userServiceFromContainer = Container.get(UserService);
userServiceFromContainer.createUser("Alice");

// Option 2: Instantiate directly, and the container will inject dependencies
const anotherUserService = new UserService();
anotherUserService.createUser("Bob");

// Verify singleton scope for logger (should show the same creation timestamp)
const logger1 = Container.get(ILogger);
const logger1Again = Container.get(ILogger);
console.log('Are logger1 and logger1Again the same instance?', logger1 === logger1Again);

view raw JSON →