diff --git a/CHANGELOG.md b/CHANGELOG.md index d0c39376..bd6d5c40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed ### Fixed +property injection tagged as @optional no longer overrides default values with `undefined`. ## [6.0.2] diff --git a/src/resolution/instantiation.ts b/src/resolution/instantiation.ts index 8e453717..66b7976b 100644 --- a/src/resolution/instantiation.ts +++ b/src/resolution/instantiation.ts @@ -68,7 +68,9 @@ function createInstanceWithInjections( args.propertyRequests.forEach((r: interfaces.Request, index: number) => { const property = r.target.identifier; const injection = args.propertyInjections[index]; - (instance as Record)[property] = injection; + if (!r.target.isOptional() || injection !== undefined) { + (instance as Record)[property] = injection; + } }); return instance } diff --git a/test/annotation/optional.test.ts b/test/annotation/optional.test.ts index 1230e813..d2e610b6 100644 --- a/test/annotation/optional.test.ts +++ b/test/annotation/optional.test.ts @@ -107,4 +107,49 @@ describe('@optional', () => { }); + it("Should allow to set a default value for class property dependencies flagged as optional", () => { + @injectable() + class Katana { + public name: string; + public constructor() { + this.name = 'Katana'; + } + } + + @injectable() + class Shuriken { + public name: string; + public constructor() { + this.name = 'Shuriken'; + } + } + + @injectable() + class Ninja { + public name: string = "Ninja"; + @inject("Katana") public katana?: Katana; + @inject("Shuriken") @optional() public shuriken: Shuriken = { + name: "DefaultShuriken", + }; + } + + const container = new Container(); + + container.bind('Katana').to(Katana); + container.bind('Ninja').to(Ninja); + + let ninja = container.get('Ninja'); + expect(ninja.name).to.eql('Ninja'); + expect(ninja.katana?.name).to.eql('Katana'); + expect(ninja.shuriken.name).to.eql('DefaultShuriken'); + + container.bind('Shuriken').to(Shuriken); + + ninja = container.get('Ninja'); + expect(ninja.name).to.eql('Ninja'); + expect(ninja.katana?.name).to.eql('Katana'); + expect(ninja.shuriken.name).to.eql('Shuriken'); + } + ); + }); \ No newline at end of file diff --git a/wiki/optional_dependencies.md b/wiki/optional_dependencies.md index 10af62a2..ab202eb5 100644 --- a/wiki/optional_dependencies.md +++ b/wiki/optional_dependencies.md @@ -84,3 +84,13 @@ class Ninja { } } ``` + +Or using properties injection: +```ts +@injectable() +class Ninja { + public name = "Ninja"; + @inject("Katana") public katana: Katana; + @inject("Shuriken") @optional() public shuriken: Shuriken = { name: "DefaultShuriken" } // Default value! +} +``` \ No newline at end of file