TypeScript IoC Container
Advantages
- battle tested 💥
- written on
typescript - simple and lightweight ❤️
- clean API 💚
- supports
tagged scopes - fully test covered 💯
- can be used with decorators
@inject - can inject properties
- can inject lazy dependencies
- composable and open to extend
Quick Start
npm install ts-ioc-container reflect-metadatanpm install ts-ioc-container reflect-metadatayarn add ts-ioc-container reflect-metadatayarn add ts-ioc-container reflect-metadataPut this in your entrypoint file (should be the first line):
import 'reflect-metadata';import 'reflect-metadata';Configure tsconfig.json:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}Creating and using a container:
import { Container, type IContainer, inject, Registration as R, select } from '../../lib';
describe('Basic usage', function () {
class Logger {
name = 'Logger';
}
it('should inject dependencies', function () {
class App {
constructor(@inject('ILogger') public logger: Logger) {}
}
const container = new Container().addRegistration(R.fromClass(Logger).bindToKey('ILogger'));
expect(container.resolve(App).logger.name).toBe('Logger');
});
it('should inject current scope', function () {
const root = new Container({ tags: ['root'] });
class App {
constructor(@inject(select.scope.current) public scope: IContainer) {}
}
const app = root.resolve(App);
expect(app.scope).toBe(root);
});
});
import { Container, type IContainer, inject, Registration as R, select } from '../../lib';
describe('Basic usage', function () {
class Logger {
name = 'Logger';
}
it('should inject dependencies', function () {
class App {
constructor(@inject('ILogger') public logger: Logger) {}
}
const container = new Container().addRegistration(R.fromClass(Logger).bindToKey('ILogger'));
expect(container.resolve(App).logger.name).toBe('Logger');
});
it('should inject current scope', function () {
const root = new Container({ tags: ['root'] });
class App {
constructor(@inject(select.scope.current) public scope: IContainer) {}
}
const app = root.resolve(App);
expect(app.scope).toBe(root);
});
});
Documentation
Browse the documentation chapters in the navigation menu to learn about:
- Overview - Core architecture and class diagrams
- Container - Core container functionality, scopes, and instance management
- Registration - Registering providers with keys and scopes
- Provider - Dependency factories with singleton, args, visibility, alias, and decorator features
- Injector - Different injection strategies (Metadata, Simple, Proxy)
- Token - Token types for dependency keys (InjectionToken, SingleToken, GroupAliasToken, etc.)
- Hooks - Lifecycle hooks for instance initialization and cleanup (onConstruct, onDispose)
Core Architecture
This chapter provides an overview of the core architecture and design of the TypeScript IoC container library. Understanding these concepts will help you make the most of the library's features.
The IoC container is built on four fundamental abstractions that work together to provide dependency injection:
Container
Manages the lifecycle and resolution of dependencies
Provider
Factory that creates dependency instances
Injector
Determines how dependencies are injected into constructors
Registration
Connects providers to containers with keys and configuration
Architecture Overview
Class Diagram
The following diagram shows the main classes and interfaces and their relationships: