cheap-di
JavaScript's dependency injection like Autofac in .Net
How to use
The recommended way of using this package is using it with code transformers like cheap-di-ts-transform
. Because in this way you will get the truly dependency injection:
abstract class Logger {
abstract debug: (message: string) => void;
}
class ConsoleLogger implements Logger {
constructor(public prefix: string) {}
debug(message: string) {
console.log(`${this.prefix}: ${message}`);
}
}
class Service {
constructor(private logger: Logger) {}
doSome() {
this.logger.debug('Hello world!');
}
}
import { container } from 'cheap-di';
const myLogPrefix = 'INFO: ';
container.registerImplementation(ConsoleLogger).as(Logger).inject(myLogPrefix);
import { container } from 'cheap-di';
const service = container.resolve(Service);
service.doSome();
But if you can't use transformers you still may use cheap-di with decorators:
import { inject } from 'cheap-di';
abstract class SessionAccessor {
abstract getSession(): string;
}
abstract class Logger {
abstract debug(message: string): void;
}
abstract class InfoLogger extends Logger {}
abstract class ErrorLogger extends Logger {}
@inject('unknown', SessionAccessor)
class ConsoleLogger implements Logger {
constructor(public prefix: string, private sessionAccessor: SessionAccessor) {}
debug(message: string) {
console.log(`[${this.sessionAccessor.getSession()}] ${this.prefix}: ${message}`);
}
}
@inject(InfoLogger)
class Service {
constructor(private logger: InfoLogger) {}
doSome() {
this.logger.debug('Hello world!');
}
}
import { container } from 'cheap-di';
const infoPrefix = 'INFO: ';
container.registerImplementation(ConsoleLogger).as(InfoLogger).inject(infoPrefix);
const errorPrefix = 'ERROR: ';
container.registerImplementation(ConsoleLogger).as(ErrorLogger).inject(errorPrefix);
import { container } from 'cheap-di';
const service = container.resolve(Service);
service.doSome();
To use stage 2 decorators you need to adjust your tsconfig.json like:
{
"compilerOptions": {
"experimentalDecorators": true
}
}
To use stage 3 decorators you don't need extra setup.
Registration variants
registerImplementation
If you would like to specify implementation of your interface:
import { container } from 'cheap-di';
abstract class Service {}
class ServiceImpl extends Service {}
container
.registerImplementation(ServiceImpl)
.as(Service);
Or if you want to inject some parameters to its constructor:
import { container } from 'cheap-di';
class Some {
constructor(private name: string) {}
}
container
.registerImplementation(Service)
.inject('some name');
Or if you want to have only one instance of the implementation class:
import { container } from 'cheap-di';
class Some {}
container
.registerImplementation(Service)
.asSingleton();
And singleton also may be used with interface specification:
import { container } from 'cheap-di';
abstract class Service {}
class ServiceImpl extends Service {}
container
.registerImplementation(ServiceImpl)
.asSingleton(Service);
And even with argument injection:
import { container } from 'cheap-di';
abstract class Service {}
class ServiceImpl extends Service {
constructor(private name: string) {
super();
}
}
container
.registerImplementation(ServiceImpl)
.asSingleton(Service)
.inject('some name');
registerInstance
If you want to register some instance as interface
import { container } from 'cheap-di';
abstract class Database {
abstract get(): Promise<string>;
}
const db: Database = {
async get() {
return Promise.resolve('name1');
},
};
container.registerInstance(db).as(Database);
You can see more examples in cheap-di/src/ContainerImpl.test.ts
Changelog