Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default values for @inject() #163

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ constructor injection.

- [TSyringe](#tsyringe)
- [Installation](#installation)
- [Babel](#babel)
- [API](#api)
- [Decorators](#decorators)
- [injectable()](#injectable)
- [singleton()](#singleton)
- [autoInjectable()](#autoinjectable)
- [inject()](#inject)
- [injectAll()](#injectall)
- [injectWithTransform()](#injectWithTransform)
- [injectAllWithTransform()](#injectAllWithTransform)
- [injectWithTransform()](#injectwithtransform)
- [injectAllWithTransform()](#injectallwithtransform)
- [scoped()](#scoped)
- [Container](#container)
- [Injection Token](#injection-token)
Expand All @@ -31,8 +32,8 @@ constructor injection.
- [Child Containers](#child-containers)
- [Clearing Instances](#clearing-instances)
- [Circular dependencies](#circular-dependencies)
- [The `delay` helper function](#the-delay-helper-function)
- [Interfaces and circular dependencies](#interfaces-and-circular-dependencies)
- [The `delay` helper function](#the-delay-helper-function)
- [Interfaces and circular dependencies](#interfaces-and-circular-dependencies)
- [Disposable instances](#disposable-instances)
- [Full examples](#full-examples)
- [Example without interfaces](#example-without-interfaces)
Expand Down Expand Up @@ -193,7 +194,7 @@ need to make the parameters optional, e.g. `database?: Database`.
### inject()

Parameter decorator factory that allows for interface and other non-class
information to be stored in the constructor's metadata.
information to be stored in the constructor's metadata. It also accepts a [provider](#providers) as a second parameter, which will be registered within the global container and can act as a fallback value in case no other registrations are done.

#### Usage

Expand Down
49 changes: 49 additions & 0 deletions src/__tests__/global-container.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,55 @@ test("allows explicit array dependencies to be resolved by inject decorator", ()
expect(bar.foo === fooArray).toBeTruthy();
});

test("allows inject to provide a default value, which will be used if not registered in other ways", () => {
@injectable()
class Foo {}

const fooArray = [new Foo()];

@injectable()
class Bar {
constructor(@inject("FooArray", {useValue: fooArray}) public foo: Foo[]) {}
}

globalContainer.register<Bar>(Bar, {useClass: Bar});

const bar = globalContainer.resolve<Bar>(Bar);
expect(bar.foo === fooArray).toBeTruthy();
});

test("allows inject to provide a default value, if injected afterwards it will be overwritten", () => {
@injectable()
class Bar {
constructor(
@inject("MyString", {useValue: "MyDefaultString"}) public foo: string
) {}
}
const str = "NewString";
globalContainer.register("MyString", {useValue: str});

globalContainer.register<Bar>(Bar, {useClass: Bar});

const bar = globalContainer.resolve<Bar>(Bar);
expect(bar.foo === str).toBeTruthy();
});

test("allows inject to have other kinds of provider", () => {
@injectable()
class Bar implements IBar {
public value = "";
}

@injectable()
class FooWithInterface {
constructor(@inject("IBar", {useClass: Bar}) public myBar: IBar) {}
}

const myFoo = globalContainer.resolve(FooWithInterface);

expect(myFoo.myBar instanceof Bar).toBeTruthy();
});

// --- @injectAll ---

test("injects all dependencies bound to a given interface", () => {
Expand Down
14 changes: 11 additions & 3 deletions src/decorators/inject.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import {defineInjectionTokenMetadata} from "../reflection-helpers";
import {instance as globalContainer} from "../dependency-container";
import {Provider} from "../providers";
import InjectionToken from "../providers/injection-token";
import {defineInjectionTokenMetadata} from "../reflection-helpers";

/**
* Parameter decorator factory that allows for interface information to be stored in the constructor's metadata
* Parameter decorator factory that allows for interface information to be stored in the constructor's metadata.
*
* If a defaultProvider is given it will be registered into the global container.
*
* @return {Function} The parameter decorator
*/
function inject(
token: InjectionToken<any>
token: InjectionToken<any>,
defaultProvider?: Provider<any>
): (target: any, propertyKey: string | symbol, parameterIndex: number) => any {
if (defaultProvider !== undefined) {
globalContainer.register(token, defaultProvider as any);
}
return defineInjectionTokenMetadata(token);
}

Expand Down