使用自动装配的Typescript依赖注入

时间:2015-10-12 19:40:12

标签: api dependency-injection typescript

是否有任何打字机框架允许用户使用java-spring autowiring中众所周知的?实施例

class A {
   public print() : void;
}

class B {
   constructor(a : A)
}
var obj = CONTAINER.get("B");

容器是API的一部分

2 个答案:

答案 0 :(得分:4)

我开发了一个名为InversifyJS的IoC容器,它具有高级依赖注入功能,如上下文绑定。

您需要按照 3个基本步骤来使用它:

1。添加注释

注释API基于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。声明绑定

绑定API基于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。解决依赖关系

决议API基于Ninject:

import kernel = from "./inversify.config";

var ninja = kernel.get<INinja>("INinja");

expect(ninja.fight()).eql("cut!"); // true
expect(ninja.sneak()).eql("hit!"); // true

最新版本(2.0.0)支持许多用例:

  • 内核模块
  • 内核中间件
  • 使用类,字符串文字或符号作为依赖标识符
  • 注入常数值
  • 注入类构造函数
  • 注入工厂
  • 自动工厂
  • 注入提供者(异步工厂)
  • 激活处理程序(用于注入代理)
  • 多次进样
  • 标记绑定
  • 自定义标签装饰器
  • 命名绑定
  • 上下文绑定
  • 友好例外(例如循环依赖)

您可以在https://github.com/inversify/InversifyJS

了解有关此内容的更多信息

2016年5月更新

在C#等编译编程语言中自动装配如下所示:

kernel.Scan(scanner =>
{
    // look for types in this assembly
    scanner.FromCallingAssembly();

    // make ISomeType bind to SomeType by default (remove the 'I'!)
    scanner.BindWith<DefaultBindingGenerator>();
});

kernel.Bind(
    x => x.FromThisAssembly()
          .SelectAllClasses()
          .BindAllInterfaces());

在TypeScript和JavaScript中没有程序集。我们可以创建一个任务,在您的模块中搜索具有@injectable()装饰器的类,但这样做效率非常低。

我们正在开发extension for InversifyJS,它允许我们认为像某种伪自动装配的东西。

而不是:

@injectable()
class Katana implements IKatana {
    public hit() {
        return "cut!";
    }
}

kernel.bind<IKatana>("IKatana").to(Katana);

你可以写:

@provide(Katana)
class Katana implements IKatana {
    public hit() {
        return "cut!";
    }
}

@provide()装饰器在引擎盖下生成绑定:

kernel.bind<Katana>(Katana).to(Katana);

该扩展程序还包含一个名为autoProvide的帮助程序,可将@provide装饰器应用于所有实体。

import * as entites from "../entities";

let kernel = new Kernel();
autoProvide(kernel, entites);
let warrior = kernel.get<Warrior>(entites.Warrior);

实体模块必须提供对所有实体的直接访问:

export { default as Warrior } from "./warrior";
export { default as Katana } from "./katana";

实体不需要@injectable@provide装饰器:

class Katana {
    public use() {
        return "Using Katana...";
    }
}

export default Katana;

但是,需要@inject装饰器:

import Katana from "./katana";
import { inject } from "inversify";

class Warrior {
    private _weapon: Katana;
    public constructor(
        // we need to declare binding because auto-provide uses
        // @injectbale decorator at runtime not compilation time
        // in the future maybe this limitation will desapear
        // thanks to design-time decorators or some other TS feature
        @inject(Katana) weapon: Katana
    ) {
        this._weapon = weapon;
    }
    public fight() {
        return this._weapon.use();
    }
}

export default Warrior;

正如我所说,这不是自动装配,因为没有装配是不可能的,但它足够接近。

您可以了解有关inversify-binding-decorators here的更多信息。

答案 1 :(得分:0)