Dependency injection in TypeScript

Sop Killen picture Sop Killen · Apr 17, 2013 · Viewed 26k times · Source

I'm looking into the possibilities to do TDD with TypeScript. If I write my tests in TypeScript, is it possible to make the import statements return mocks for my class under test? Or is the only feasible approach to write the tests in pure javascript and deal with injecting AMDs myself?

Answer

Remo H. Jansen picture Remo H. Jansen · Apr 19, 2016

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