What it is
tsyringe is a lightweight dependency injection container for TypeScript from Microsoft, using decorators and constructor injection.
Mark classes @injectable and resolve them from the container. Interfaces need a token, because TypeScript interfaces do not exist at runtime.
Installation
npm install tsyringe reflect-metadataGetting started
The smallest useful thing you can do with it, and what each part means.
typescript
import 'reflect-metadata';
import { injectable, singleton, container } from 'tsyringe';
@singleton()
class Database { query(sql: string) { /* … */ } }
@injectable()
class BookService {
constructor(private db: Database) {} // resolved by type
find(id: string) { return this.db.query('SELECT …'); }
}
const service = container.resolve(BookService);Advanced usage
Where the library earns its place over a simpler alternative.
typescript
interface Mailer { send(to: string, body: string): Promise<void>; }
// Interfaces vanish at runtime, so a token is required.
export const MAILER = Symbol('Mailer');
@injectable()
class NotificationService {
constructor(@inject(MAILER) private mailer: Mailer) {}
}
container.register<Mailer>(MAILER, { useClass: SmtpMailer });
// Tests swap the implementation without touching the consumer.
const testContainer = container.createChildContainer();
testContainer.register<Mailer>(MAILER, { useValue: fakeMailer });Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Cannot inject the dependency at position 0
- The parameter is an interface or an unregistered type. Add an @inject token and register it.
- TypeInfo not known for the class
- The class lacks @injectable, or emitDecoratorMetadata is off in tsconfig.
Best practices
- Import 'reflect-metadata' exactly once, at the very top of the entry point.
- Use a Symbol token for every interface — type-based resolution cannot work for them.
- Use child containers in tests instead of mutating the global container.
- Resolve at the composition root only; calling container.resolve deep in the code is the service-locator anti-pattern.
Background
Why it exists, and what it was reacting to.
Built by Microsoft for teams wanting the testability of dependency injection without adopting a full framework such as NestJS or InversifyJS.
