What it is
InversifyJS is a full-featured inversion of control container for TypeScript, with decorators, scopes, tagged bindings and middleware.
Bind interfaces to implementations in a container using symbol identifiers, then resolve the composition root. Scopes control instance lifetime.
Installation
npm install inversify reflect-metadataGetting started
The smallest useful thing you can do with it, and what each part means.
typescript
import 'reflect-metadata';
import { Container, injectable, inject } from 'inversify';
const TYPES = { Mailer: Symbol.for('Mailer'), Store: Symbol.for('Store') };
@injectable()
class SmtpMailer implements Mailer { /* … */ }
@injectable()
class NotificationService {
constructor(@inject(TYPES.Mailer) private mailer: Mailer) {}
}
const container = new Container();
container.bind<Mailer>(TYPES.Mailer).to(SmtpMailer).inSingletonScope();
container.bind(NotificationService).toSelf();
const service = container.get(NotificationService);Advanced usage
Where the library earns its place over a simpler alternative.
typescript
// Pick an implementation based on where it is being injected.
container.bind<Logger>(TYPES.Logger)
.to(FileLogger)
.whenInjectedInto(BatchProcessor);
container.bind<Logger>(TYPES.Logger)
.to(ConsoleLogger)
.when((request) => !request.parentRequest);
// Tests: snapshot, override, restore.
container.snapshot();
container.rebind<Mailer>(TYPES.Mailer).toConstantValue(fakeMailer);
// … run the test …
container.restore();Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- No matching bindings found for serviceIdentifier
- The symbol was never bound, or a different symbol instance was used. Symbol.for returns the same symbol for a given key; Symbol() does not.
- Missing required @injectable annotation
- Every class the container constructs needs the decorator, including ones bound with toSelf.
Best practices
- Use Symbol.for for identifiers so they are collision-free and minification-safe.
- Import reflect-metadata once, first, at the entry point.
- Resolve only at the composition root; resolving deep in the code is a service locator.
- Prefer tsyringe if you only need basic constructor injection — Inversify is considerably heavier.
Background
Why it exists, and what it was reacting to.
InversifyJS predates most TypeScript DI containers and remains the most feature-complete, offering contextual and conditional bindings that lighter containers do not.
