多重注入

原文链接

当有两个以上的具体类型绑定了一个抽象时,我们可以使用多重注入(multi-injection)。多亏有@multiInject装饰器,我们才能够将Weapon数组通过Ninja类的构造器进行注入:

interface Weapon {
    name: string;
}

@injectable()
class Katana implements Weapon {
    public name = "Katana";
}

@injectable()
class Shuriken implements Weapon {
    public name = "Shuriken";
}

interface Ninja {
    katana: Weapon;
    shuriken: Weapon;
}

@injectable()
class Ninja implements Ninja {
    public katana: Weapon;
    public shuriken: Weapon;
    public constructor(
	    @multiInject("Weapon") weapons: Weapon[]
    ) {
        this.katana = weapons[0];
        this.shuriken = weapons[1];
    }
}
1
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

我们将KatanaShuriken绑定到Weapon

container.bind<Ninja>("Ninja").to(Ninja);
container.bind<Weapon>("Weapon").to(Katana);
container.bind<Weapon>("Weapon").to(Shuriken);
1
2
3

关于扩展运算符(...)

在InversifyJS的早期版本中,扩展运算符(...)通常会不起作用而且不会抛出任何错误。这显然是我们无法接受的,因此开发组做出了修复,允许您使用扩展运算符注入数组。但我们并不推荐这么做,因为它看起来没什么用。

您可以像下面这样使用@multiInject...

@injectable()
class Foo {
    public bar: Bar[];
    constructor(@multiInject(BAR) ...args: Bar[][]) {
        // args will always contain one unique item the value of that item is a Bar[] 
        this.bar = args[0];
    }
}
1
2
3
4
5
6
7
8

这里有一个问题,args的类型被定义为Bar[][],这是因为multiInject会将注入项使用数组进行包裹而扩展运算符也会这么做。其结果就是注入项被数组包裹了两层。

我们尝试过解决这个问题,可惜的是唯一的解决办法是通过@spread()装饰器生成一些额外的元数据。

@injectable()
class Foo {
    public bar: Bar[];
    constructor(@multiInject(BAR) @spread() ...args: Bar[]) {
        this.bar = args[0];
    }
}
1
2
3
4
5
6
7

于是我们放弃了这个想法。基于没有其他方法可以实现某些功能时最好使用装饰器的思想,我们只使用@multiInject而不使用...其实就能够达成预期效果了,这么做反而更简单。

@injectable()
class Foo {
    public bar: Bar[];
    constructor(@multiInject(BAR) args: Bar[]) {
        this.bar = args;
    }
}
1
2
3
4
5
6
7
上次更新: 1/5/2020, 1:11:10 PM