I've gone through the documentation of Aurelia DI and looked at the source code and wanted to share what I'm trying to achieve so that I can be shot down if I'm missing something obvious. I've looked at the samples here for TS with Aurelia but I can't see how it will work, and the docs are lacking.
What I want is:
dataProvider.js (the data provider interface)
export interface DataProvider {
getData(): number;
}
itemDisplayer1.js (a class that will consume an injected class that implements the interface)
import {inject} from 'aurelia-framework';
import {DataProvider} from './dataProvider';
@inject(DataProvider)
export class itemDisplayer1 {
constructor(public dataProvider: DataProvider) {
this.dataProvider = dataProvider;
this.data = dataProvider.getData();
}
}
itemDisplayer2.js (another class that will consume an injected class that implements the interface)
import {inject} from 'aurelia-framework';
import {DataProvider} from './dataProvider';
@inject(DataProvider)
export class itemDisplayer2 {
constructor(public dataProvider: DataProvider) {
this.dataProvider = dataProvider;
this.data = dataProvider.getData();
}
}
GoodDataProvider.js
import {DataProvider} from "./dataProvider";
export class GoodDataProvider implements DataProvider {
data = 1;
getData() {
return this.data;
}
}
BetterDataProvider.js
import {DataProvider} from "./dataProvider";
export class BetterDataProvider implements DataProvider {
data = 2;
getData() {
return this.data;
}
}
And then somewhere(?) I would like to configure that itemDisplayer1 should be provided with an instance of GoodDataProvider and itemDisplayer2 should be provided with an instance of BetterDataProvider (1).
Then comes the problem of DI context. I'm not sure how to use container.createChild(). There's not much info on it that I can find. It creates a child container and it will delegate back to the parent when needed, but if I create 2 child containers and register one of the 2 providers with each child container, how would the itemDisplayer classes know which one to use (without changing their definitions and injecting in the parent container etc)?
Note: The lifetime management information doesn't live in the consumers or the providers of the dependencies (this is often done in the Aurelia DI examples and seems a little manufactured). I would expect this to be able to be defined when the consumers and providers are associated - point '(1)' above.
In summary, is this possible? Is this something that is on the cards for the near-ish future? Should I be trying to replace Aurelia DI with a custom container that meets my needs?
(The reason I'm trying to do this is that in order to evaluate js frameworks, the frameworks need to demonstrate a mature DI system with lifetime management/AOP etc capabilities as one of the criteria)
from @eisenbergeffect: The DI is going to get some internal overhaul once we get the benchmarks written.
But on a related note, it can’t work with interfaces because TypeScript compiles those away at runtime.
You would have to come up with unique keys when you register your different types in the DI container and then specify the appropriate unique key in the @Inject(xxx) statement. The keys can be anything you like. Normally folks use the type itself for the unique key (this causes some confusion), but you could use strings, numbers, or anything else you like.
the unit tests are informative also: https://github.com/aurelia/dependency-injection/blob/master/test/container.spec.js