Skip to content

Introduction ​

@nodelibraries/ioc is a lightweight, type-safe Inversion of Control (IoC) container for Node.js and TypeScript, inspired by .NET Core's dependency injection system. It provides dependency injection capabilities similar to .NET's built-in DI container, but designed specifically for TypeScript/JavaScript.

@nodelibraries/ioc - A lightweight, type-safe IoC container designed for Node.js and TypeScript. Learn more in our About page.

Key Features ​

  • 🎯 Type-safe - Full TypeScript support with type inference
  • 📜 JavaScript Support - Works with both TypeScript and JavaScript
  • 🔄 Multiple Lifetimes - Singleton, Scoped, and Transient service lifetimes
  • 🏗️ Dependency Injection - Automatic dependency resolution
  • 📦 Lightweight - Zero dependencies
  • 🎨 Flexible Registration - Register both concrete classes and abstract interfaces
  • 🚫 No Decorators - Clean code without decorator pollution
  • 🏭 Factory Pattern - Support for factory functions and async initialization
  • 🔢 Multiple Implementations - Register and retrieve multiple implementations
  • 🔑 Keyed Services - Key-based service lookup (with getRequiredKeyedService)
  • ✅ TryAdd Pattern - Safe registration without overriding
  • 🛡️ Scope Validation - Detect lifetime mismatches at build time (validateScopes & validateOnBuild)
  • 🔄 Circular Dependencies - Automatic resolution of circular dependencies for all lifetimes
  • 🔍 Service Checking - Check service existence with isService() without resolving
  • 🗑️ Service Management - Remove, replace, and manage services dynamically
  • 🔄 Lifecycle Hooks - onInit() and onDestroy() callbacks for service initialization and cleanup
  • 💎 Value Registration - Register pre-created values (JSON, primitives, instances)

What is Dependency Injection? ​

Dependency Injection (DI) is a design pattern where objects receive their dependencies from an external source rather than creating them internally. This makes your code more modular, testable, and maintainable.

Without Dependency Injection ​

typescript
class UserService {
  private logger = new Logger(); // Tight coupling!

  getUsers() {
    this.logger.log('Fetching users...');
    return [];
  }
}

With Dependency Injection ​

typescript
class UserService {
  constructor(private logger: ILogger) {} // Loose coupling!

  getUsers() {
    this.logger.log('Fetching users...');
    return [];
  }
}

Why Use an IoC Container? ​

An IoC container manages the creation and lifetime of your services, automatically resolving dependencies. This means:

  1. Less boilerplate - No need to manually wire dependencies
  2. Better testability - Easy to mock dependencies in tests
  3. Lifetime management - Automatic handling of singleton, scoped, and transient services
  4. Type safety - Compile-time checking of dependencies

Comparison with .NET DI ​

This container is inspired by .NET's dependency injection system. It provides similar features:

  • ✅ Singleton, Scoped, Transient lifetimes
  • ✅ Factory pattern support
  • ✅ Multiple implementations
  • ✅ Keyed services (with getRequiredKeyedService)
  • ✅ TryAdd pattern
  • ✅ Scope validation (validateScopes & validateOnBuild)
  • ✅ Service checking (isService)
  • ✅ Service management (remove, removeAll, replace)
  • ✅ Lifecycle hooks
  • ✅ Value registration
  • ✅ Circular dependency support

For a detailed comparison, see the COMPARISON.md file in the repository.

Next Steps ​

Released under the ISC License. If you find this project helpful, consider buying me a coffee ☕