Lightweight dependency injection container for JavaScript/TypeScript
npx @tessl/cli install tessl/npm-tsyringe@4.10.0TSyringe is a lightweight dependency injection container for TypeScript/JavaScript that enables constructor injection for building modular, testable applications. It provides comprehensive decorators for marking classes and parameters, supports multiple provider types for flexible service registration, and offers advanced features like scoped lifecycles, child containers, and interception hooks.
npm install tsyringe reflect-metadataimport "reflect-metadata"; // Required polyfill
import { container, injectable, singleton, inject } from "tsyringe";For CommonJS:
require("reflect-metadata");
const { container, injectable, singleton, inject } = require("tsyringe");Note: TSyringe requires the reflect-metadata polyfill to be imported at the top of your entry point.
import "reflect-metadata";
import { container, injectable, singleton, inject } from "tsyringe";
// Define services
@injectable()
class Logger {
log(message: string) {
console.log(message);
}
}
@injectable()
class UserService {
constructor(private logger: Logger) {}
getUser(id: string) {
this.logger.log(`Getting user ${id}`);
return { id, name: "John Doe" };
}
}
// Register and resolve
container.register("UserService", UserService);
const userService = container.resolve<UserService>("UserService");
const user = userService.getUser("123");TSyringe is built around several key components:
Core container interface providing dependency registration, resolution, and lifecycle management. Supports hierarchical child containers and disposal patterns.
interface DependencyContainer extends Disposable {
// Registration methods (overloaded)
register<T>(token: InjectionToken<T>, provider: Provider<T>, options?: RegistrationOptions): DependencyContainer;
// Singleton registration
registerSingleton<T>(from: InjectionToken<T>, to: InjectionToken<T>): DependencyContainer;
registerSingleton<T>(token: constructor<T>): DependencyContainer;
// Type registration
registerType<T>(from: InjectionToken<T>, to: InjectionToken<T>): DependencyContainer;
// Instance registration
registerInstance<T>(token: InjectionToken<T>, instance: T): DependencyContainer;
// Resolution methods
resolve<T>(token: InjectionToken<T>): T;
resolveAll<T>(token: InjectionToken<T>): T[];
// Registration check
isRegistered<T>(token: InjectionToken<T>, recursive?: boolean): boolean;
// Container management
reset(): void;
clearInstances(): void;
createChildContainer(): DependencyContainer;
// Interception
beforeResolution<T>(
token: InjectionToken<T>,
callback: PreResolutionInterceptorCallback<T>,
options?: InterceptorOptions
): void;
afterResolution<T>(
token: InjectionToken<T>,
callback: PostResolutionInterceptorCallback<T>,
options?: InterceptorOptions
): void;
}
// Global container instance
const container: DependencyContainer;Decorators for marking classes as injectable, defining lifecycle behavior, and configuring automatic registration.
function injectable<T>(options?: {token?: InjectionToken<T> | InjectionToken<T>[]}): ClassDecorator;
function singleton<T>(): ClassDecorator;
function scoped<T>(lifecycle: Lifecycle.ContainerScoped | Lifecycle.ResolutionScoped, token?: InjectionToken<T>): ClassDecorator;
function autoInjectable(): ClassDecorator;
function registry(registrations: ({token: InjectionToken; options?: RegistrationOptions} & Provider<any>)[]): ClassDecorator;Decorators for parameter-level dependency injection, enabling fine-grained control over individual constructor and method parameters.
function inject(token: InjectionToken<any>, options?: {isOptional?: boolean}): ParameterDecorator;
function injectAll(token: InjectionToken<any>, options?: {isOptional?: boolean}): ParameterDecorator;
function injectWithTransform(
token: InjectionToken<any>,
transformer: InjectionToken<Transform<any, any>>,
...args: any[]
): ParameterDecorator;
function injectAllWithTransform(
token: InjectionToken<any>,
transformer: InjectionToken<Transform<[any], any>>,
...args: any[]
): ParameterDecorator;Flexible provider types for registering dependencies using different patterns (class constructors, factory functions, concrete values, or token aliases).
type Provider<T> = ClassProvider<T> | FactoryProvider<T> | ValueProvider<T> | TokenProvider<T>;
interface ClassProvider<T> {
useClass: constructor<T> | DelayedConstructor<T>;
}
interface FactoryProvider<T> {
useFactory: (dependencyContainer: DependencyContainer) => T;
}
interface ValueProvider<T> {
useValue: T;
}
interface TokenProvider<T> {
useToken: InjectionToken<T>;
}Comprehensive lifecycle management with multiple scopes, registration options, and disposable resource handling.
enum Lifecycle {
Transient = 0,
Singleton = 1,
ResolutionScoped = 2,
ContainerScoped = 3
}
interface RegistrationOptions {
lifecycle: Lifecycle;
}
interface Disposable {
dispose(): Promise<void> | void;
}Advanced factory utilities for caching strategies and conditional instantiation patterns.
type FactoryFunction<T> = (dependencyContainer: DependencyContainer) => T;
function instanceCachingFactory<T>(factoryFunc: FactoryFunction<T>): FactoryFunction<T>;
function instancePerContainerCachingFactory<T>(factoryFunc: FactoryFunction<T>): FactoryFunction<T>;
function predicateAwareClassFactory<T>(
predicate: (dependencyContainer: DependencyContainer) => boolean,
trueConstructor: constructor<T>,
falseConstructor: constructor<T>,
useCaching?: boolean
): FactoryFunction<T>;Lazy initialization utilities for circular dependency resolution and delayed constructor instantiation.
function delay<T>(wrappedConstructor: () => constructor<T>): DelayedConstructor<T>;
class DelayedConstructor<T> {
createProxy(createObject: (ctor: constructor<T>) => T): T;
}// Core injection token type
type InjectionToken<T> = constructor<T> | string | symbol | DelayedConstructor<T>;
// Constructor function type
type constructor<T> = {new (...args: any[]): T};
// Frequency for interceptors
type Frequency = "Always" | "Once";
// Resolution types
type ResolutionType = "Single" | "All";
// Interceptor callback types
type PreResolutionInterceptorCallback<T> = (
token: InjectionToken<T>,
resolutionType: ResolutionType
) => void;
type PostResolutionInterceptorCallback<T> = (
token: InjectionToken<T>,
result: T | T[],
resolutionType: ResolutionType
) => void;
// Interceptor options
interface InterceptorOptions {
frequency: Frequency;
}
// Transform interface for dependency transformation
interface Transform<TIn, TOut> {
transform: (incoming: TIn, ...args: any[]) => TOut;
}
// Factory function type
type FactoryFunction<T> = (dependencyContainer: DependencyContainer) => T;