Skip to main content

Binding Syntax

Binding syntax is provided as a fluent interface provided as the result of using the container API or the container module API

BindingToSyntax

interface BindingToSyntax<T> {
// ...
}

Represents a service binding given a service identifier.

const bindingToSyntax = container.bind('service-id');

Further docs refers to this service identifier as the "given service identifier".

to

to(constructor: interfaces.Newable<T>): interfaces.BindingInWhenOnSyntax<T>;

Binds a class instantiation to the given service binding. Whenever the service is resolved, the class constructor will be invoked in order to build the resolved value.

const container: Container = new Container();
container.bind<Weapon>('Weapon').to(Katana);

const katana: Weapon = container.get<Weapon>('Weapon');

toSelf

toSelf(): interfaces.BindingInWhenOnSyntax<T>;

If the given service identifier is a class, establish a type binding to that class.

const container: Container = new Container();
container.bind<Weapon>(Katana).toSelf();

const katana: Weapon = container.get<Weapon>(Katana);

toConstantValue

toConstantValue(value: T): interfaces.BindingWhenOnSyntax<T>;

Binds a value in singleton scope to the given service identifier.

const container: Container = new Container();
container.bind<Weapon>('Weapon').toConstantValue(new Katana());

const katana: Weapon = container.get<Weapon>('Weapon');

toDynamicValue

toDynamicValue(func: interfaces.DynamicValue<T>): interfaces.BindingInWhenOnSyntax<T>;

Binds a function to the given service id. Whenever the service is resolved, the function passed will be invoked in order to build the resolved value.

info

Keep in mind a service is not resolved if it's cached in the current scope.

const container: Container = new Container();
container.bind<Weapon>('Weapon').toDynamicValue((): Weapon => new Katana());

const katana: Weapon = container.get<Weapon>('Weapon');

toConstructor

toConstructor<T2>(constructor: interfaces.Newable<T2>): interfaces.BindingWhenOnSyntax<T>;

Binds a class to the given service id. Whenever the service is resolved, the class constructor will be passed as the resolved value.

const container: Container = new Container();
container.bind<Weapon>('WeaponConstructor').toConstructor(Katana);

const katanaConstructor: interfaces.Newable<Weapon> =
container.get<interfaces.Newable<Weapon>>('WeaponConstructor');

toFactory

toFactory<T2>(factory: interfaces.FactoryCreator<T2>): interfaces.BindingWhenOnSyntax<T>;

Binds a factory to the given service identifier. Whenever the service is resolved, the factory will be passed as the resolved value.

container.bind<Engine>('Engine').to(PetrolEngine).whenTargetNamed('petrol');
container.bind<Engine>('Engine').to(DieselEngine).whenTargetNamed('diesel');

container
.bind<interfaces.Factory<Engine>>('Factory<Engine>')
.toFactory<Engine, [string], [number]>((context: interfaces.Context) => {
return (named: string) => (displacement: number) => {
const engine: Engine = context.container.getNamed<Engine>(
'Engine',
named,
);
engine.displacement = displacement;
return engine;
};
});

@injectable()
class DieselCarFactory implements CarFactory {
readonly #dieselFactory: (displacement: number) => Engine;

constructor(
@inject('Factory<Engine>')
factory: (category: string) => (displacement: number) => Engine, // Injecting an engine factory
) {
// Creating a diesel engine factory
this.#dieselFactory = factory('diesel');
}

public createEngine(displacement: number): Engine {
// Creating a concrete diesel engine
return this.#dieselFactory(displacement);
}
}

toFunction

toFunction(func: T): interfaces.BindingWhenOnSyntax<T>;

An alias of BindingToSyntax.toConstantValue restricted to functions.

toAutoFactory

toAutoFactory<T2>(serviceIdentifier: interfaces.ServiceIdentifier<T2>): interfaces.BindingWhenOnSyntax<T>;

Binds a factory of services asociated a target service identifier to the given service identifier.

@injectable()
class Ninja implements Ninja {
readonly #katana: Katana;
readonly #shuriken: Shuriken;

constructor(
@inject('Factory<Katana>') katanaFactory: interfaces.AutoFactory<Katana>,
@inject('Shuriken') shuriken: Shuriken,
) {
this.#katana = katanaFactory();
this.#shuriken = shuriken;
}

public fight() {
return this.#katana.hit();
}

public sneak() {
return this.#shuriken.throw();
}
}
container.bind('Katana').to(Katana);
container.bind('Shuriken').to(Shuriken);

container
.bind<interfaces.Factory<Katana>>('Factory<Katana>')
.toAutoFactory<Katana>('Katana');

container.bind(Ninja).toSelf();

toAutoNamedFactory

toAutoNamedFactory<T2>(serviceIdentifier: interfaces.ServiceIdentifier<T2>): BindingWhenOnSyntax<T>;

Binds a factory of services asociated a target service identifier and a name to the given service identifier.

@injectable()
class Ninja implements Ninja {
readonly #katana: Katana;
readonly #shuriken: Shuriken;

constructor(
@inject('Factory<Weapon>')
katanaFactory: interfaces.AutoNamedFactory<Weapon>,
) {
this.#katana = katanaFactory('katana') as Katana;
this.#shuriken = katanaFactory('shuriken') as Shuriken;
}

public fight() {
return this.#katana.hit();
}

public sneak() {
return this.#shuriken.throw();
}
}
container.bind<Weapon>('Weapon').to(Katana).whenTargetNamed('katana');
container.bind<Weapon>('Weapon').to(Shuriken).whenTargetNamed('shuriken');
container
.bind<interfaces.AutoNamedFactory<Weapon>>('Factory<Weapon>')
.toAutoNamedFactory<Weapon>('Weapon');

container.bind(Ninja).toSelf();

toProvider

toProvider<T2>(provider: interfaces.ProviderCreator<T2>): interfaces.BindingWhenOnSyntax<T>;

Binds a provider of services asociated a target service identifier to the given service identifier. A provider is just an asyncronous factory.

const container: Container = new Container();

interface Sword {
material: string;
damage: number;
}

@injectable()
class Katana implements Sword {
public material!: string;
public damage!: number;
}

type SwordProvider = (material: string, damage: number) => Promise<Sword>;

container.bind<Sword>('Sword').to(Katana);

container
.bind<SwordProvider>('SwordProvider')
.toProvider<Sword>((context: interfaces.Context) => {
return async (material: string, damage: number): Promise<Sword> => {
// Custom args!
return new Promise<Sword>(
(resolve: (value: Sword | PromiseLike<Sword>) => void) => {
setTimeout(() => {
const katana: Sword = context.container.get<Sword>('Sword');
katana.material = material;
katana.damage = damage;
resolve(katana);
}, 10);
},
);
};
});

const katanaProvider: SwordProvider =
container.get<SwordProvider>('SwordProvider');

const powerfulGoldKatana: Promise<Sword> = katanaProvider('gold', 100);

const notSoPowerfulGoldKatana: Promise<Sword> = katanaProvider('gold', 10);

toService

toService(service: interfaces.ServiceIdentifier<T>): void;

Binds the services bound to a target service identifier to the given service identifier.

const container: Container = new Container();

container.bind(lorcanaCardCatalogProviderSymbol).to(LorcanaCardCatalogProvider);
container.bind(mtgCardCatalogProviderSymbol).to(MtgCardCatalogProvider);

container
.bind(cardCatalogProviderSymbol)
.toService(lorcanaCardCatalogProviderSymbol);
container
.bind(cardCatalogProviderSymbol)
.toService(mtgCardCatalogProviderSymbol);

const cardCatalogProviders: CardCatalogProvider<unknown>[] = container.getAll(
cardCatalogProviderSymbol,
);

BindingInSyntax

interface BindingInSyntax<T> {
// ...
}

Represents a service binding given a service identifier and a service resolution such as a contructor, a factory or a provider.

inSingletonScope

inSingletonScope(): BindingWhenOnSyntax<T>;

Sets the binding scope to singleton. Consider docs as reference.

inTransientScope

inTransientScope(): BindingWhenOnSyntax<T>;

Sets the binding scope to transient. Consider docs as reference.

inRequestScope

inRequestScope(): BindingWhenOnSyntax<T>;

Sets the binding scope to request. Consider docs as reference.

BindingOnSyntax

interface BindingOnSyntax<T> {
// ...
}

Allows setting binding activation and deactivation handlers.

onActivation

onActivation(fn: (context: Context, injectable: T) => T | Promise<T>): BindingWhenSyntax<T>;

Sets a binding activation handler. The activation handler is invoked after a dependency has been resolved and before it is added to a scope cache. The activation handler will not be invoked if the dependency is taken from a scope cache.

@injectable()
class Katana {
public use(): string {
return 'hit!';
}
}

container
.bind<Katana>('Katana')
.to(Katana)
.onActivation((_context: interfaces.Context, katana: Katana) => {
const handler: ProxyHandler<() => string> = {
apply: function (
target: () => string,
thisArgument: unknown,
argumentsList: [],
) {
console.log(`Starting: ${new Date().getTime().toString()}`);
const result: string = target.apply(thisArgument, argumentsList);
console.log(`Finished: ${new Date().getTime().toString()}`);
return result;
},
};

katana.use = new Proxy(katana.use.bind(katana), handler);

return katana;
});

onDeactivation

onDeactivation(fn: (injectable: T) => void | Promise<void>): BindingWhenSyntax<T>;

Sets a binding deactivation handler on a singleton scope binding. The deactivation handler is caled when the binding is unbound from a container.

BindingWhenSyntax

interface BindingWhenSyntax<T> {
// ...
}

Allows setting binding constraints.

when

Sets a constraint for the current binding.

when(constraint: (request: Request) => boolean): BindingOnSyntax<T>;
const ninjaId: symbol = Symbol.for('Ninja');
const weaponId: symbol = Symbol.for('Weapon');

@injectable()
class Ninja {
constructor(
@inject(weaponId)
@named('shuriken')
public readonly weapon: Weapon,
) {}
}

container.bind<Ninja>(ninjaId).to(Ninja);

const whenTargetNamedConstraint: (
name: string,
) => (request: interfaces.Request) => boolean =
(name: string) =>
(request: interfaces.Request): boolean =>
request.target.matchesNamedTag(name);

container
.bind<Weapon>(weaponId)
.to(Katana)
.when(whenTargetNamedConstraint('katana'));

container
.bind<Weapon>(weaponId)
.to(Shuriken)
.when(whenTargetNamedConstraint('shuriken'));

const ninja: Ninja = container.get(ninjaId);

// Returns 5
const ninjaDamage: number = ninja.weapon.damage;

In the previous example, a custom constraint is implemented to use the binding if and only if the target name is a certain one.

whenTargetNamed

Constraints the binding to be used if and only if the target name is a certain one.

whenTargetNamed(name: string | number | symbol): BindingOnSyntax<T>;

whenTargetIsDefault

whenTargetIsDefault(): BindingOnSyntax<T>;

Constraints the binding to be used if and only if the target has no name nor tags.

whenTargetTagged

whenTargetTagged(tag: string | number | symbol, value: unknown): BindingOnSyntax<T>;

Constraints the binding to be used if and only if the target tag is a certain one.

whenInjectedInto

whenInjectedInto(parent: NewableFunction | string): BindingOnSyntax<T>;

Constraints the binding to be used if and only if the parent target service identifier is a certain one.

whenParentNamed

whenParentNamed(name: string | number | symbol): BindingOnSyntax<T>;

Constraints the binding to be used if and only if the parent target name is a certain one.

whenParentTagged

whenParentTagged(tag: string | number | symbol, value: unknown): BindingOnSyntax<T>;

Constraints the binding to be used if and only if the parent target tag is a certain one.

whenAnyAncestorIs

whenAnyAncestorIs(ancestor: NewableFunction | string): BindingOnSyntax<T>;

Constraints the binding to be used if and only if any ancestor target service identifier is a certain one.

whenNoAncestorIs

whenNoAncestorIs(ancestor: NewableFunction | string): BindingOnSyntax<T>;

Constraints the binding to be used if and only if no ancestor target service identifier is a certain one.

whenAnyAncestorNamed

whenAnyAncestorNamed(name: string | number | symbol): BindingOnSyntax<T>;

Constraints the binding to be used if and only if any ancestor target name is a certain one.

whenAnyAncestorTagged

whenAnyAncestorTagged(tag: string | number | symbol, value: unknown): BindingOnSyntax<T>;

Constraints the binding to be used if and only if any ancestor target tag is a certain one.

whenNoAncestorNamed

whenNoAncestorNamed(name: string | number | symbol): BindingOnSyntax<T>;

Constraints the binding to be used if and only if no ancestor target name is a certain one.

whenNoAncestorTagged

whenNoAncestorTagged(tag: string | number | symbol, value: unknown): BindingOnSyntax<T>;

Constraints the binding to be used if and only if no ancestor target tag is a certain one.

whenAnyAncestorMatches

whenAnyAncestorMatches(constraint: (request: Request) => boolean): BindingOnSyntax<T>;

Constraints the binding to be used if and only if any ancestor matches a certain constraint.

whenNoAncestorMatches

whenNoAncestorMatches(constraint: (request: Request) => boolean): BindingOnSyntax<T>;

Constraints the binding to be used if and only if no ancestor matches a certain constraint.

BindingWhenOnSyntax

The union of BindingWhenSyntax and BindingOnSyntax

export interface BindingWhenOnSyntax<T>
extends BindingWhenSyntax<T>,
BindingOnSyntax<T> {}

BindingInWhenOnSyntax

The union of BindingInSyntax and BindingWhenOnSyntax.

export interface BindingInWhenOnSyntax<T>
extends BindingInSyntax<T>,
BindingWhenOnSyntax<T> {}