inversify / InversifyJS

A powerful and lightweight inversion of control container for JavaScript & Node.js apps powered by TypeScript.
http://inversify.io/
MIT License
11.29k stars 716 forks source link

Ability to inject parent injectors in hierarchical di #622

Open amcdnl opened 7 years ago

amcdnl commented 7 years ago

Requirement

In Angular's DI system you can create hierarchical containers as you describe here: https://github.com/inversify/InversifyJS/blob/master/wiki/hierarchical_di.md

I'd like to do the same and it seems this is possible but I'm not sure how I can safely get a reference to the parent container without creating a circular loop in the module resolution.

For example, If I were to do: App.ts

const container = new Container();
[...providers, App].forEach(p => container.bind(p).toSelf());
container.get<App>(App).bootstrap();

then in my child container:

Api.ts

import { parentContainer } from './app';
const container = new Container();
// container.parent = parentContainer;
controllers.forEach(p => container.bind(p).toSelf());

the problem is my hierarchy of files is like: App -> Http -> Api and by including App in my Api file it would create a circular. Angular's DI system handles this very nicely by allowing you to inject the injector like:

class Api {
  constructor(private injector: Injector) {} // <- Parent injector
}

this allows me safely import the injector without having to import the original container, and its a tad nicer api too :).

ajafff commented 6 years ago

I'm also in the need of this feature.

Though I'm a little confused by the different names used in the description above. @amcdnl Do you want a new abstraction named Injector added? Or do you actually only want to inject the Container and Injector is just used to show how Angular does that?

So your code from above would then become:

class Api {
  constructor(parent: Container) {
    const container = new Container();
    container.parent = parent;
    controllers.forEach(p => container.bind(p).toSelf());
  }
}

@remojansen would you accept a PR that adds an identifier Container to every Container instance that resolves to this instance? That could be considered a breaking change as it might break users that already provide a binding for Container. To avoid that one could introduce a new identifier ParentContainer or similar.