is a Dependency Injection / Inversion of Control (IoC) container package for Javascript and Node.js applications powered by Typescript . It manages the dependencies between classes, so that applications stay easy to change and maintain as they grow.
Features:
- Well-known Angular DI API.
- No external dependencies.
- Life Time control.
- Hierarchical containers.
- Resolves values using Classes, Factories and Values.
- Descriptive error messages.
- 97% test coverage.
Examples:
Installation:
npm install --save container-ioc
Basics:
Code examples below are written in Typescript. Check examples/javascript for examples written in Javascript.
Step 1. Define your interfaces and types.
Possible values for types: Symbol, string, Object.
interface IApplication { run(): void; } interface IService { serve(): void; } const TApplication = Symbol('IApplication'); const TService = Symbol('IService');
Step 2. Declare dependencies with decorators Injectable and Inject.
import { Injectable, Inject } from 'container-ioc'; @Injectable() export class Application implements IApplication { constructor(@Inject(TService) private service: IService) {} run(): void { this.service.serve(); } } @Injectable() export class Service implements IService { serve(): void { // serves } }
Step 3. Create a container and register types in there.
import { Container } from 'container-ioc'; let container = new Container(); container.register([ { token: TApplication, useClass: Application }, { token: TService, useClass: Service } ]);
Step 4. Resolve value from the container.
let app = container.resolve(TApplication); app.run();
Step 2 for Javascript.
Since Javascript does not support parameter decorators, use alternative API for declaring dependencies. In this case we don't use Inject decorator. See examples/javascript for more.
@Injectable([TService]) class Service { constructor(service) { this.service = service; } }
Life Time control
By default, containers resolve singletons when using useClass and useFactory. Default life time for all items in a container can be set by passing an option object to it's contructor with defailtLifeTime attribute. Possible values: LifeTime.PerRequest (resolves instances) and LifeTime.Persistent (resolves singletons);
import { LifeTime } from 'container-ioc'; const container = new Container({ defaultLifeTime: LifeTime.PerRequest });
You can also specify life time individually for each item in a container by specifying lifeTime attribute.
container.register([ { token: TService, useClass: Service, lifeTime: LifeTime.PerRequest } ]);
container.register([ { token: TService, useFactory: () => { return { serve(): void {} } }, lifeTime: LifeTime.Persistent } ]);
Hierarchical containers
If a container can't find a value within itself, it will look it up in ascendant containers. There a 3 ways to set a parent for a container.
1. Container.createChild() method.
const parentContainer = new Container(); const childContainer = parentContainer.createChild();
2. Container.setParent() method.
const parent = new Container(); const child = new Container(); child.setParent(parent);
3. Via Container's constructor with options.
const parent = new Container(); const child = new Container({ parent: parent });
Using Factories
/* Without injections */ container.register([ { token: 'TokenForFactory', useFactory: () => { return 'any-value'; } } ]); /* With injections */ container.register([ { token: 'EnvProvider', useClass: EnvProvider }, { token: 'TokenForFactory', useFactory: (envProvider) => { // do something return 'something'; }, inject: ['EnvProvider'] } ]);
Using Values
container.register([ { token: 'IConfig', useValue: {}} ]);
Shortcut for Classes
container.register([ App ]);
Is the same as:
container.register([ { token: App, useClass: App } ]);
Contribution
Become a contributor to this project. Feel free to submit an issue or a pull request.
see CONTRIBUTION.md for more information.
Please see also our Code of Conduct.
