With TypeScript now we have static analyze and many OOP features in JavaScript. So it's also time to have better unit tests in client side logic and as well we need IOC container for dependency injections to make code more testable...
So, have someone already experienced it this subject or maybe know libraries for typescript or JavaScript frameworks that can be porting to TypeScript?
Inversion of Control (IoC): a design pattern that stipulates frameworks should call userland code, instead of userland code calling library code. Dependency injection (DI): a variant of IoC in which objects receive other objects as dependencies instead of constructors or setters.
The D letter in SOLID is the Dependency Inversion principle. It helps to decouple modules from each other so that you can easily swap one part of the code for another. One of the techniques that helps to follow this principle is Dependency Injection.
This is termed as IOC(Inversion of Control) where control is being inverted to the external entity. Angular offers such a system that helps not only to register but also to instantiate component dependencies.
Dependency Injection is the method of providing the dependencies and Inversion of Control is the end result of Dependency Injection. IoC is a design principle where the control flow of the program is inverted. Dependency Injection is one of the subtypes of the IOC principle.
I have developed an IoC container called InversifyJS with advanced dependency injection features like contextual bindings.
You need to follow 3 basic steps to use it:
The annotation API is based on Angular 2.0:
import { injectable, inject } from "inversify";
@injectable()
class Katana implements IKatana {
public hit() {
return "cut!";
}
}
@injectable()
class Shuriken implements IShuriken {
public throw() {
return "hit!";
}
}
@injectable()
class Ninja implements INinja {
private _katana: IKatana;
private _shuriken: IShuriken;
public constructor(
@inject("IKatana") katana: IKatana,
@inject("IShuriken") shuriken: IShuriken
) {
this._katana = katana;
this._shuriken = shuriken;
}
public fight() { return this._katana.hit(); };
public sneak() { return this._shuriken.throw(); };
}
The binding API is based on Ninject:
import { Kernel } from "inversify";
import { Ninja } from "./entities/ninja";
import { Katana } from "./entities/katana";
import { Shuriken} from "./entities/shuriken";
var kernel = new Kernel();
kernel.bind<INinja>("INinja").to(Ninja);
kernel.bind<IKatana>("IKatana").to(Katana);
kernel.bind<IShuriken>("IShuriken").to(Shuriken);
export default kernel;
The resolution API is based on Ninject:
import kernel = from "./inversify.config";
var ninja = kernel.get<INinja>("INinja");
expect(ninja.fight()).eql("cut!"); // true
expect(ninja.sneak()).eql("hit!"); // true
The latest release (2.0.0) supports many use cases:
You can learn more about it at https://github.com/inversify/InversifyJS
Alternatively you can just use no framework and use class as container with object factories as properties. You can then inherit this class in tests and change factories. This approach is type safe and do not require any decorators, just registration of classes.
class B {
echo() {
alert('test');
}
}
class A {
constructor(private b: B) {
b.echo();
}
}
class Container {
A = () => new A(this.B());
B = singleton(() => new B());
}
var c = new Container();
var a = c.A();
// singleton helper:
function memoize<T>(factory: () => T): () => T {
var memo: T = null;
return function () {
if(!memo) {
memo = factory();
}
return memo;
};
}
var singleton = memoize;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With