thiagobustamante / typescript-ioc

A Lightweight annotation-based dependency injection container for typescript.
MIT License
526 stars 64 forks source link

Multi-injection support #28

Open julianosam opened 6 years ago

julianosam commented 6 years ago

Hey guys! I am heavily using this library in one of my projects, and just ran into a good use case for multi-injection. More specifically, I want to to something like (pseudo code):

  // Provide the implementations, holding them all inside the container
  Container.bind(MyAbstractClass).add(MyConcreteClass1);
  Container.bind(MyAbstractClass).add(MyConcreteClass2);

   // Inject all registered implementations
   constructor(
      @MultiInject private _allImplementations: MyAbstractClass[]
  ) { }
  1. Just to make sure, is there some way to achieve this today that I am missing?
  2. If not, do you guys think it would be a good feature to add?

Let me know your thoughts!

thiagobustamante commented 6 years ago

Hi @julianosam ,

It is not possible with the current version, but I like the idea. We can think something to next release

doronguttman commented 6 years ago

I had the same requirement and found a workaround:

// components/base.ts
export abstract class BaseClass {
}
// components/impl1.ts
import { Provides } from "typescript-ioc";
import { BaseClass } from "./base";

@Provides(BaseClass)
export class ImplClass1 extends BaseClass {
}
// components/impl2.ts
import { Provides } from "typescript-ioc";
import { BaseClass } from "./base";

@Provides(BaseClass)
export class ImplClass2 extends BaseClass {
}
// components/index.ts
import { Container } from "typescript-ioc";
import { BaseClass } from "./base";
import { ImplClass1 } from "./impl1";
import { ImplClass2 } from "./impl2";

// this is where the magic happens
export class ImplCollection extends Array<BaseClass> {
  constructor() {
    super();
    this.push(Container.get(ImplClass1) as BaseClass);
    this.push(Container.get(ImplClass2) as BaseClass);
  }
}
// main.ts
import { AutoWired, Inject } from "typescript-ioc";
import { ImplCollection } from "./components/index";

@AutoWired
class Consumer {
  @Inject
  private implementations: ImplCollection;
}

let consumer = new Consumer();
HarelM commented 5 years ago

Any updates on this? While the given workaround will achieve the required behavior I think it should work out of the box for a dependency injection container. I have yet to work with an ioc container that doesn't support this feature. This usually comes with a "named" injection - i.e something like the following:

@Name('A')
@Provies(BaseClass)
export class A extend BaseClass { ... }

Then you can do something like
export class B {
    @inject('A') 
    public _myBaseBlassWhichIsA: BaseClass;
}

Below is an example (described in a test) of the unity container behavior with names and multiple implementations: http://www.tomdupont.net/2014/02/understanding-unity-named-registration.html

nemcikjan commented 4 years ago

any intentions to implement this?

dustinlacewell commented 3 years ago

Aw, just ran into this.