inversify-binding-decorators
允许开发者使用ES2016装饰器来声明InversifyJS绑定的工具:
安装
您可以使用npm进行安装
npm install inversify inversify-binding-decorators reflect-metadata --save
inversify-binding-decorator
类型定义包含在了npm模块中,TypeScript版本要求是2.0以上。请参阅InversifyJS文档以了解更多关于安装过程的信息。
基础
InversifyJS的API让我们声明绑定时更加流畅:
import { injectable, Container } from "inversify";
import "reflect-metadata";
@injectable()
class Katana implements Weapon {
public hit() {
return "cut!";
}
}
@injectable()
class Shuriken implements ThrowableWeapon {
public throw() {
return "hit!";
}
}
var container = new Container();
container.bind<Katana>("Katana").to(Katana);
container.bind<Shuriken>("Shuriken").to(Shuriken);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
该库可以让您使用装饰器语法来声明绑定:
import { injectable, Container } from "inversify";
import { provide, buildProviderModule } from "inversify-binding-decorators";
import "reflect-metadata";
@provide(Katana)
class Katana implements Weapon {
public hit() {
return "cut!";
}
}
@provide(Shuriken)
class Shuriken implements ThrowableWeapon {
public throw() {
return "hit!";
}
}
var container = new Container();
// Reflects all decorators provided by this package and packages them into a module to be loaded by the container
// 它代表了这个包所提供的所有装饰器,并将它们打包为一个模块以便容器加载。
container.load(buildProviderModule());
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@provide
的情况
多次使用如果您尝试多次使用@provide
:
@provide("Ninja")
@provide("SilentNinja")
class Ninja {
// ...
}
2
3
4
5
该库会抛出一个错误:
Cannot apply @injectable decorator multiple times. Please use @provide(ID, true) if you are trying to declare multiple bindings!
我们这么做是防止您误操作多次使用@provide
装饰器:
您可以通过将第二个参数force
设置为true
来绕过这个检测:
@provide("Ninja", true)
@provide("SilentNinja", true)
class Ninja {
// ...
}
2
3
4
5
使用类、字符串和symbol作为标识符
当您用类作为标识符来调用@provide
时:
@provide(Katana)
class Katana {
public hit() {
return "cut!";
}
}
@provide(Ninja)
class Ninja {
private _katana: Weapon;
public constructor(
katana: Weapon
) {
this._katana = katana;
}
public fight() { return this._katana.hit(); };
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
会在暗处创建一个新的绑定:
container.bind<Katana>(Katana).to(Katana);
container.bind<Ninja>(Ninja).to(Ninja);
2
除了类,使用字符串作为标识符也是可以的:
let TYPE = {
IKatana: "Katana",
INinja: "Ninja"
};
@provide(TYPE.Katana)
class Katana implements Weapon {
public hit() {
return "cut!";
}
}
@provide(TYPE.Ninja)
class Ninja implements Ninja {
private _katana: Weapon;
public constructor(
@inject(TYPE.Katana) katana: Weapon
) {
this._katana = katana;
}
public fight() { return this._katana.hit(); };
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
还可以使用Symbol
作为标识符:
let TYPE = {
Katana: Symbol("Katana"),
Ninja: Symbol("Ninja")
};
@provide(TYPE.Katana)
class Katana implements Weapon {
public hit() {
return "cut!";
}
}
@provide(TYPE.Ninja)
class Ninja implements Ninja {
private _katana: Weapon;
public constructor(
@inject(TYPE.Katana) katana: Weapon
) {
this._katana = katana;
}
public fight() { return this._katana.hit(); };
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
连续绑定装饰器
基本的@provide
装饰器并不允许声明上下文约束、作用域和其他高级绑定功能。为此,我们提供了另一个装饰器,它允许您使用连续的语法绑定所有的功能:
import { injectable, Container } from "inversify";
import { fluentProvide, buildProviderModule } from "inversify-binding-decorators";
let TYPE = {
Weapon : "Weapon",
Ninja: "Ninja"
};
@fluentProvide(TYPE.Weapon).whenTargetTagged("throwable", true).done();
class Katana implements Weapon {
public hit() {
return "cut!";
}
}
@fluentProvide(TYPE.Weapon).whenTargetTagged("throwable", false).done();
class Shuriken implements Weapon {
public hit() {
return "hit!";
}
}
@fluentProvide(TYPE.Ninja).done();
class Ninja implements Ninja {
private _katana: Weapon;
private _shuriken: Weapon;
public constructor(
@inject(TYPE.Weapon) @tagged("throwable", false) katana: Weapon,
@inject(TYPE.Weapon) @tagged("throwable", true) shuriken: ThrowableWeapon
) {
this._katana = katana;
this._shuriken = shuriken;
}
public fight() { return this._katana.hit(); };
public sneak() { return this._shuriken.throw(); };
}
var container = new Container();
container.load(buildProviderModule());
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
您可以为连续装饰器创建别名来满足您的需求:
let provideThrowable = function(identifier, isThrowable) {
return provide(identifier)
.whenTargetTagged("throwable", isThrowable)
.done();
};
@provideThrowable(TYPE.Weapon, true)
class Katana implements Weapon {
public hit() {
return "cut!";
}
}
@provideThrowable(TYPE.Weapon, false)
class Shuriken implements Weapon {
public hit() {
return "hit!";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
另一个示例:
let provideSingleton = function(identifier) {
return provide(identifier)
.inSingletonScope()
.done();
};
@provideSingleton(TYPE.Weapon)
class Shuriken implements Weapon {
public hit() {
return "hit!";
}
}
2
3
4
5
6
7
8
9
10
11
12
@fluentProvide
装饰器
多次使用如果多次使用@fluentProvide
装饰器:
let container = new Container();
const provideSingleton = (identifier: any) => {
return fluentProvide(identifier)
.inSingletonScope()
.done();
};
function shouldThrow() {
@provideSingleton("Ninja")
@provideSingleton("SilentNinja")
class Ninja {}
return Ninja;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
同样我们会抛出一个错误:
Cannot apply @fluentProvide decorator multiple times but is has been used multiple times in Ninja Please use done(true) if you are trying to declare multiple bindings!
我们这么做是防止您误操作多次使用@fluentProvide
装饰器:
您可以通过向done()
方法传递true
来绕过这个检测:
const provideSingleton = (identifier: any) => {
return fluentProvide(identifier)
.inSingletonScope()
.done(true); // IMPORTANT! 重要!
};
function shouldThrow() {
@provideSingleton("Ninja")
@provideSingleton("SilentNinja")
class Ninja {}
return Ninja;
}
let container = new Container();
container.load(buildProviderModule());
2
3
4
5
6
7
8
9
10
11
12
13
14
自动provide工具
本库提供了一个小的工具,方便您向模块的所有公共属性添加默认的@provide
装饰器:
考虑一下下面这个例子:
import * as entites from "../entities";
let container = new Container();
autoProvide(container, entites);
let warrior = container.get(entites.Warrior);
expect(warrior.fight()).eql("Using Katana...");
2
3
4
5
6
entities.ts文件的内容类似下面这种:
export { default as Warrior } from "./warrior";
export { default as Katana } from "./katana";
2
katana.ts文件长这样:
class Katana {
public use() {
return "Using Katana...";
}
}
export default Katana;
2
3
4
5
6
7
warrior.ts文件长这样:
import Katana from "./katana";
import { inject } from "inversify";
class Warrior {
private _weapon: Weapon;
public constructor(
// we need to declare binding because auto-provide uses @injectable decorator at runtime not compilation time
// in the future maybe this limitation will desapear thanks to design-time decorators or some other TS feature
// 因为auto-provide是在运行时而非编译时使用的@injectable装饰器,因此我们需要声明绑定
@inject(Katana) weapon: Weapon
) {
this._weapon = weapon;
}
public fight() {
return this._weapon.use();
}
}
export default Warrior;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19