Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IOC for TypeScript

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?

like image 655
Denis Agarev Avatar asked Oct 09 '12 08:10

Denis Agarev


People also ask

What is IoC in 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.

Does TypeScript have dependency injection?

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.

What is IoC in angular?

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.

Is IoC the same as dependency injection?

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.


2 Answers

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:

1. Add annotations

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(); };

}

2. Declare bindings

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;

3. Resolve dependencies

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:

  • Kernel modules
  • Kernel middleware
  • Use classes, string literals or Symbols as dependency identifiers
  • Injection of constant values
  • Injection of class constructors
  • Injection of factories
  • Auto factory
  • Injection of providers (async factory)
  • Activation handlers (used to inject proxies)
  • Multi injections
  • Tagged bindings
  • Custom tag decorators
  • Named bindings
  • Contextual bindings
  • Friendly exceptions (e.g. Circular dependencies)

You can learn more about it at https://github.com/inversify/InversifyJS

like image 145
Remo H. Jansen Avatar answered Nov 16 '22 01:11

Remo H. Jansen


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;
like image 33
jka Avatar answered Nov 16 '22 03:11

jka