diff --git a/README.md b/README.md index ce8c1129d..02efb523b 100644 --- a/README.md +++ b/README.md @@ -391,7 +391,7 @@ class Ninja implements INinja { private _shuriken: IShuriken; public constructor( - @inject("IFactory") katanaFactory: IFactory, + @inject("IFactory") katanaFactory: () => IKatana, @inject("IShuriken") shuriken: IShuriken ) { this._katana = katanaFactory(); @@ -411,7 +411,9 @@ kernel.bind>("IFactory").toFactory((context) }; }); ``` + You can also define a Factory with args: + ```ts kernel.bind>("IFactory").toFactory((context) => { return (throwable: boolean) => { @@ -424,6 +426,33 @@ kernel.bind>("IFactory").toFactory((context) }); ``` +Sometimes you might need to pass arguments to a factory in different moments during the execution: +```ts +kernel.bind("IEngine").to(PetrolEngine).whenTargetNamed("petrol"); +kernel.bind("IEngine").to(DieselEngine).whenTargetNamed("diesel"); + +kernel.bind>("IFactory").toFactory((context) => { + return (named: string) => (displacement: number) => { + let engine = context.kernel.getNamed("IEngine", named); + engine.displacement = displacement; + return engine; + }; +}); + +@injectable() +class DieselCarFactory implements ICarFactory { + private _dieselFactory: (displacement: number) => IEngine ; + constructor( + @inject("IFactory") factory: (category: string) => (displacement: number) => IEngine + ) { + this._dieselFactory = factory("diesel"); + } + public createEngine(displacement: number): IEngine { + return this._dieselFactory(displacement); + } +} +``` + #### Auto factory Binds an abstraction to a auto-generated Factory. ```ts diff --git a/package.json b/package.json index 1f148eff8..84540abe9 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "gulp-sourcemaps": "^1.6.0", "gulp-tslint": "^5.0.0", "gulp-typedoc": "^1.2.1", - "gulp-typescript": "^2.12.1", + "gulp-typescript": "^2.13.0", "gulp-uglify": "^1.5.1", "harmonize": "^1.4.4", "harmony-proxy": "^1.0.0", @@ -57,7 +57,7 @@ "sinon": "^1.17.3", "tsify": "^0.15.2", "tslint": "^3.2.2", - "typescript": "^1.7.5", + "typescript": "^1.8.10", "vinyl-buffer": "^1.0.0", "vinyl-source-stream": "^1.1.0", "wallabify": "0.0.14" diff --git a/src/interfaces/bindings/factory.d.ts b/src/interfaces/bindings/factory.d.ts index 1aa745bc6..35a8492ff 100644 --- a/src/interfaces/bindings/factory.d.ts +++ b/src/interfaces/bindings/factory.d.ts @@ -1,5 +1,5 @@ /// interface IFactory extends Function { - (...args: any[]): T; + (...args: any[]): (((...args: any[]) => T)|T); } diff --git a/test/inversify.test.ts b/test/inversify.test.ts index 9db336ed3..f89d138d7 100644 --- a/test/inversify.test.ts +++ b/test/inversify.test.ts @@ -566,7 +566,7 @@ describe("InversifyJS", () => { private _shuriken: IShuriken; public constructor( - @inject("IFactory") katanaFactory: IFactory, + @inject("IFactory") katanaFactory: () => IKatana, @inject("IShuriken") shuriken: IShuriken ) { this._katana = katanaFactory(); @@ -627,7 +627,7 @@ describe("InversifyJS", () => { private _shuriken: IWeapon; public constructor( - @inject("IFactory") weaponFactory: IFactory + @inject("IFactory") weaponFactory: (throwable: boolean) => IWeapon ) { this._katana = weaponFactory(false); this._shuriken = weaponFactory(true); @@ -659,6 +659,87 @@ describe("InversifyJS", () => { }); + it("Should support the injection of user defined factories with partial application", () => { + + interface IInjectorPump {} + + @injectable() + class InjectorPump implements IInjectorPump {} + + interface ISparkPlugs {} + + @injectable() + class SparkPlugs implements ISparkPlugs {} + + class IEngine { + public displacement: number; + } + + @injectable() + class DieselEngine implements IEngine { + public displacement: number; + private _injectorPump: IInjectorPump; + constructor( + @inject("IInjectorPump") injectorPump: IInjectorPump + ) { + this._injectorPump = injectorPump; + this.displacement = null; + } + } + + @injectable() + class PetrolEngine implements IEngine { + public displacement: number; + private _sparkPlugs: ISparkPlugs; + constructor( + @inject("ISparkPlugs") sparkPlugs: ISparkPlugs + ) { + this._sparkPlugs = sparkPlugs; + this.displacement = null; + } + } + + interface ICarFactory { + createEngine(displacement: number): IEngine; + } + + @injectable() + class DieselCarFactory implements ICarFactory { + private _dieselFactory: (displacement: number) => IEngine ; + constructor( + @inject("IFactory") factory: (category: string) => (displacement: number) => IEngine + ) { + this._dieselFactory = factory("diesel"); + } + public createEngine(displacement: number): IEngine { + return this._dieselFactory(displacement); + } + } + + let kernel = new Kernel(); + kernel.bind("ISparkPlugs").to(SparkPlugs); + kernel.bind("IInjectorPump").to(InjectorPump); + kernel.bind("IEngine").to(PetrolEngine).whenTargetNamed("petrol"); + kernel.bind("IEngine").to(DieselEngine).whenTargetNamed("diesel"); + + kernel.bind>("IFactory").toFactory((context) => { + return (named: string) => (displacement: number) => { + let engine = context.kernel.getNamed("IEngine", named); + engine.displacement = displacement; + return engine; + }; + }); + + kernel.bind("IDieselCarFactory").to(DieselCarFactory); + + let dieselCarFactory = kernel.get("IDieselCarFactory"); + let engine = dieselCarFactory.createEngine(300); + + expect(engine.displacement).eql(300); + expect(engine instanceof DieselEngine).eql(true); + + }); + it("Should support the injection of auto factories", () => { interface INinja { @@ -695,7 +776,7 @@ describe("InversifyJS", () => { private _shuriken: IShuriken; public constructor( - @inject("IFactory") katanaAutoFactory: IFactory, + @inject("IFactory") katanaAutoFactory: () => IKatana, @inject("IShuriken") shuriken: IShuriken ) { this._katana = katanaAutoFactory(); diff --git a/type_definitions/inversify/inversify.d.ts b/type_definitions/inversify/inversify.d.ts index 662640d6c..6a2f63be9 100644 --- a/type_definitions/inversify/inversify.d.ts +++ b/type_definitions/inversify/inversify.d.ts @@ -83,7 +83,7 @@ declare namespace inversify { interface IBindingWhenOnSyntax extends IBindingWhenSyntax, IBindingOnSyntax {} export interface IFactory extends Function { - (...args: any[]): T; + (...args: any[]): (((...args: any[]) => T)|T); } interface IFactoryCreator extends Function {