Multi-injection
We can use multi-injection When two or more concretions have been bound to the an abstraction.
Notice how an array of Weapon
is injected into the Ninja
class via its constructor thanks to the usage of the @multiInject
decorator:
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];
}
}
We are binding Katana
and Shuriken
to Weapon
:
container.bind<Ninja>("Ninja").to(Ninja);
container.bind<Weapon>("Weapon").to(Katana);
container.bind<Weapon>("Weapon").to(Shuriken);
About the spread ...
operator
In early releases of InversifyJS the spread operator used to fail without throwing any errors. That was not acceptable and we implemented a fix that allows you to inject arrays using the spread operator. However it is not recommended because it turns out to be a bit useless.
You can inject using @multiInject
and ...
as follows:
@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];
}
}
The main problem is that this requires the type of args
to be Bar[][]
because multiInject will wrap the injections using an array and the spread
operator will do the same. As a result the injection is wrapped by an array
two times.
We tried to solve this problem but the only way was to generate some additional
metadata using a @spread()
decorator.
@injectable()
class Foo {
public bar: Bar[];
constructor(@multiInject(BAR) @spread() ...args: Bar[]) {
this.bar = args[0];
}
}
We discarded this idea because it is better to use decorators when there is not
other way to achieve something. In this case there is a much simpler way to
achieve the desired result. We just need to use @multiInject
and avoid using ...
:
@injectable()
class Foo {
public bar: Bar[];
constructor(@multiInject(BAR) args: Bar[]) {
this.bar = args;
}
}