Be able to inject dependencies into properties:
class SomeService {}
class SomeWebComponent {
@inject(SomeService)
private _service: SomeService;
public doSomething() {
let count = this._service.count;
this._service.increment();
return count;
}
}
In a property injection the following:
@inject(SomeService)
Is identical to:
kernel.get<any>(SomeService)
Just like the bind method:
interface IKernel {
bind<T>(serviceIdentifier: (string|Symbol|INewable<T>)): IBindingToSyntax<T>;
// ...
}
It should allow string, Symbol and INewable<T> as identifier:
let ISomeService = "ISomeService";
class SomeWebComponent {
@inject(ISomeService)
private _service: ISomeService;
public doSomething() {
let count = this._service.count;
this._service.increment();
return count;
}
}
// or
let ISomeService = Symbol("ISomeService");
class SomeWebComponent {
@inject(ISomeService)
private _service: ISomeService;
public doSomething() {
let count = this._service.count;
this._service.increment();
return count;
}
}
Named and tagged bindings should be supported if possible:
kernel.bind<IWeapon>(IWeapon).to(Shuriken).whenTargetNamed("throwable");
kernel.bind<IWeapon>(IWeapon).to(Katana).whenTargetNamed("not-throwable");
class Warrior {
// AKA kernel.getNamed<any>(IWeapon, "throwable")
@injectNamed(IWeapon, "throwable")
@named("throwable")
private _weapon: IWeapon;
public fight() {
this._weapon.use();
}
}
kernel.bind<IWeapon>(IWeapon).to(Shuriken).whenTargetTagged("throwable", true);
kernel.bind<IWeapon>(IWeapon).to(Katana).whenTargeTagged("throwable", false);
class Warrior {
// AKA kernel.getTagged<any>(IWeapon, "throwable", true)
@injectTagged(IWeapon, "throwable", true)
@tagged("throwable", true)
private _weapon: IWeapon;
public fight() {
this._weapon.use();
}
}
We also need @multiInject as a property decorator:
let inject = makePropertyInjectDecorator(kernel);
let multiInject = makePropertyMultiInjectDecorator(kernel);
class Warrior {
@inject(Katana)
public katana: Katana;
}
class Warrior {
@multiInject(IWeapon)
public weapons: IWeapon[];
}
It should support contextual bindings:
kernel.bind<IWeapon>("IWeapon").to(Katana).when((request: IRequest) => {
return request.target.name.equals("_primaryWeapon");
});
kernel.bind<IWeapon>("IWeapon").to(Shuriken).when((request: IRequest) => {
return request.target.name.equals("_secondaryWeapon");
});
class Ninja {
// AKA kernel.get<any>(IWeapon)
@inject(IWeapon)
@paramName("_primaryWeapon") // rename to @targetName ?
private _primaryWeapon: IWeapon;
public fight() {
this._primaryWeapon.use();
}
}
It is likely that the property injection context will look as the following:
--- Context
--- Kernel
--- Request
--- ID = IWeapon
--- TARGET
--- NAME = "_weapon"
--- SERVICE = IWeapon
We can't add a parent request (Ninja) to the context because then the resolver will try to resolve the ninja (as opposed to resolve the weapon).
This means that only a few contextual constraints will be supported by property injection:
interface IBindingWhenSyntax<T> {
when(constraint: (request: IRequest) => boolean): IBindingOnSyntax<T>; // OK
whenTargetNamed(name: string): IBindingOnSyntax<T>; // OK
whenTargetTagged(tag: string, value: any): IBindingOnSyntax<T>; // OK
whenInjectedInto(parent: (Function|string)): IBindingOnSyntax<T>; // NOT SUPPORTED
whenParentNamed(name: string): IBindingOnSyntax<T>; // NOT SUPPORTED
whenParentTagged(tag: string, value: any): IBindingOnSyntax<T>; // NOT SUPPORTED
whenAnyAncestorIs(ancestor: (Function|string)): IBindingOnSyntax<T>; // NOT SUPPORTED
whenNoAncestorIs(ancestor: (Function|string)): IBindingOnSyntax<T>; // NOT SUPPORTED
whenAnyAncestorNamed(name: string): IBindingOnSyntax<T>; // NOT SUPPORTED
whenAnyAncestorTagged(tag: string, value: any): IBindingOnSyntax<T>; // NOT SUPPORTED
whenNoAncestorNamed(name: string): IBindingOnSyntax<T>; // NOT SUPPORTED
whenNoAncestorTagged(tag: string, value: any): IBindingOnSyntax<T>; // NOT SUPPORTED
whenAnyAncestorMatches(constraint: (request: IRequest) => boolean): IBindingOnSyntax<T>; // NOT SUPPORTED
whenNoAncestorMatches(constraint: (request: IRequest) => boolean): IBindingOnSyntax<T>; // NOT SUPPORTED
}
Multiple properties could be injected:
export class Settings extends Component<SettingsProps, {}> {
@inject(MyService)
private myService: MyService;
@inject(MyService)
private myService2: MyService;
render() {}
}
Each property will have its own instance.
Property injection is not supported.
We need to create a new @inject property decorator. This decorator needs access to a kernel:
let kernel = new Kernel();
kernel.bind<SomeService>(SomeService).to(SomeService);
let inject= makeInjectPropertyDecorator(kernel);
This feature was proposed by @otbe on #187
Property injection is now available in [email protected] ⭐ 🎉 documentation is available here.
Most helpful comment
Property injection is now available in
[email protected]⭐ 🎉 documentation is available here.