jeringa
v1.0.0-20250226115528.commit-9b7214f
Published
A lightweight, reflection-based dependency injection library for TypeScript.
Downloads
679
Readme
Jeringa
A lightweight, reflection-based dependency injection library for TypeScript.
Installation
npm install jeringa
Features
- Type-safe dependency injection using TypeScript decorators and metadata reflection
- Automatic resolution of dependency graphs
- Support for named dependencies with
@InjectByName
- Cycle detection in dependency graphs
- Compatible with class inheritance and complex class hierarchies
- Visualization of dependency graphs with GraphViz
Requirements
- TypeScript 4.x or higher
reflect-metadata
for type information- Enable
experimentalDecorators
andemitDecoratorMetadata
in yourtsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Basic Usage
import { Inject, injectDependencies } from 'jeringa';
import 'reflect-metadata';
// Define your classes with the @Inject decorator
@Inject
class Database {
connect() {
return 'Connected to database';
}
}
@Inject
class UserService {
constructor(private db: Database) {}
getUsers() {
this.db.connect();
return ['User1', 'User2'];
}
}
@Inject
class Application {
constructor(private userService: UserService) {}
run() {
return this.userService.getUsers();
}
}
// Bootstrap your application
async function bootstrap() {
const app = await injectDependencies(Application);
console.log(app.run()); // ['User1', 'User2']
}
bootstrap();
Named Dependencies
Use @InjectByName
when you need to inject dependencies by name:
import { Inject, InjectByName, injectDependencies } from 'jeringa';
@Inject
class ConfiguredService {
constructor(
@InjectByName('config') private config: any
) {}
getApiKey() {
return this.config.apiKey;
}
}
@Inject
class Application {
constructor(private service: ConfiguredService) {}
run() {
return this.service.getApiKey();
}
}
// Provide named dependencies when bootstrapping
async function bootstrap() {
const app = await injectDependencies(Application, {
config: { apiKey: 'secret-key-123' }
});
console.log(app.run()); // 'secret-key-123'
}
bootstrap();
Working with Inheritance
Jeringa correctly handles inheritance chains:
@Inject
class BaseService {
constructor(@InjectByName('logger') protected logger: any) {}
log(message: string) {
this.logger.info(message);
}
}
@Inject
class ExtendedService extends BaseService {
// Inherits the constructor and its injections
logExtended(message: string) {
this.log(`Extended: ${message}`);
}
}
// The logger dependency will be properly injected into ExtendedService
const service = await injectDependencies(ExtendedService, {
logger: { info: console.log }
});
Visualizing Dependency Graphs
Jeringa provides a utility to generate GraphViz visualizations of your dependency graph:
import { createDependencyGraph, getGraphViz } from 'jeringa';
const graph = createDependencyGraph(Application);
const dotGraph = getGraphViz(graph);
// Output the DOT format string to visualize with GraphViz tools
console.log(dotGraph);
API Reference
Decorators
@Inject
: Class decorator to mark a class as injectable@InjectByName(name: string)
: Parameter decorator to inject dependencies by name
Functions
injectDependencies<T>(ctor: Constructor<T>, providedDependenciesByName?: Record<string, any>): Promise<T>
Bootstrap your application by creating an instance of the specified class with all dependencies resolvedcreateDependencyGraph(ctor: Constructor): DependencyGraph
Create a dependency graph for analysis or visualizationgetGraphViz(graph: DependencyGraph): string
Generate a GraphViz DOT format representation of the dependency graph
Error Handling
Jeringa provides helpful error messages for common issues:
- Circular dependencies
- Missing named dependencies
- Missing type information (when decorators or metadata are not properly configured)