A dependency injection library based on IoC
Container. Dependency Injection
implementation for Node.js projects written with Typescript
. Build a container and permit it for all dependencies. Get all injectable objects easily without use new
keyword. It's light-weight library and easy-to-use.
Installation
npm i @decouplejs/core
And add below to compilerOptions
in tsconfig.json
"experimentalDecorators": true
Usage
Lets think about you have two classes which are UserController
and UserService
.
UserController
have a dependency to UserService
which is declared with @inject
decorator.
export class UserController {
constructor(
@inject(USER_SERVICE)
private userService: UserService
) {}
print() {
console.log("UserController");
this.userService.print();
}
}
export class UserService {
constructor() {}
print() {
console.log("UserService");
}
}
When we used @inject
decorator, USER_SERVICE
binding key was declared. Lets define this binding keys.
Create a keys.ts
file and define binding keys to be associated with above classes like below:
export const USER_CONTROLLER = BindingKey.create("user.controller");
export const USER_SERVICE = BindingKey.create("user.service");
Now, create a Container
and introduce your classes to IoC Container via its .injectable()
function with binding keys that are defined before.
const container = new Container();
container.injectable(USER_CONTROLLER, UserController);
container.injectable(USER_SERVICE, UserService);
Finally, if you want to create and use a UserController
instance, call .get()
of Container with USER_CONTROLLER
key.
const controller = container.get(USER_CONTROLLER);
controller.print();
// output
// UserController
// UserService
@inject decorator
export class UserController {
constructor(
@inject(USER_SERVICE)
private userService: UserService
) {}
// ...
}
With @inject
decorator, decouple.js understand which dependent classes instances will be initialize and assign during create a new base class instance.
You can also use `@inject' decorator as property decorator like constructor parameter decorator as below.
export class UserController {
@inject(USER_SERVICE)
private userService: UserService;
constructor() {}
// ...
}
Binding Scopes
Specifies how long the created objects will live and how many times they should be created during the application lifecycle. Scopes can be defined by two way:
- via
.scope()
function while class is introducing with.injectable()
container.injectable(USER_CONTROLLER, UserController).scope(BindingScope.SINGLETON);
- via
@injectable
decorator which is above class definition
@injectable(BindingScope.SINGLETON)
export class UserController {
// ...
}
One of scope definition methods is enough for a injectable class.
If two methods are used at the same time, the scope of method 1 will be valid.
If no scope is specified, the TRANSIENT scope will be valid.
Decouple.js supports two types of scope for now:
SINGLETON
Only one instance will be created during the application lifecycle and this same instance will be used by all dependent classes too.
TRANSIENT
A new instance will be created for each need of the class instance.
Example Implementation
Next Features
- express.js middleware support.
- BindingScope.REQUEST support
License
Copyright © 2022 Abdulkadir Dede.
This project is licensed under the MIT License - see the LICENSE file for details.