Skip to main content
Version: Next

Binding Syntax

Binding syntax is provided as a fluent interface resulting from using the container API or the container module API.

BoundServiceSyntax​

interface BoundServiceSyntax {
getIdentifier(): BindingIdentifier;
}

Base interface implemented by all binding syntax interfaces. Provides access to the binding's unique identifier.

getIdentifier​

getIdentifier(): BindingIdentifier;

Returns a unique identifier for this specific binding. This identifier can be used with container.unbind() to remove just this binding, rather than all bindings for a service.

Example:

const container: Container = new Container();

// The identifier can be used to unbind this specific binding later
export const bindingIdentifier: BindingIdentifier = container
.bind('MyService')
.to(MyServiceImpl)
.getIdentifier();

BindToFluentSyntax​

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

Represents a service binding given a service identifier.

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

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

to​

to(type: Newable<T>): BindInWhenOnFluentSyntax<T>;

Binds a class instantiation to the given service binding. Whenever the service is resolved, the class constructor will be invoked 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(): BindInWhenOnFluentSyntax<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): BindWhenOnFluentSyntax<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(builder: DynamicValueBuilder<T>): BindInWhenOnFluentSyntax<T>;

Binds a function to the given service identifier. Whenever the service is resolved, the function passed will be invoked 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');

toFactory​

toFactory(
factory: T extends Factory<unknown, any>
? (context: ResolutionContext) => T | Promise<T>
: never,
): BindWhenOnFluentSyntax<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).whenNamed('petrol');
container.bind<Engine>('Engine').to(DieselEngine).whenNamed('diesel');

container
.bind<Factory<(displacement: number) => Engine, [string]>>('Factory<Engine>')
.toFactory((context: ResolutionContext) => {
return (named: string) => (displacement: number) => {
const engine: Engine = context.get<Engine>('Engine', {
name: 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);
}
}

toResolvedValue​

toResolvedValue(factory: () => T | Promise<T>): BindInWhenOnFluentSyntax<T>;
toResolvedValue<TArgs extends unknown[] = any[]>(
factory: (...args: TArgs) => T | Promise<T>,
injectOptions: MapToResolvedValueInjectOptions<TArgs>,
): BindInWhenOnFluentSyntax<T>;

Binds a value to a service identifier. This value is generated on top of a function that receives resolved services. You can specify the services to be resolved by passing the service identifiers as arguments:

const container: Container = new Container();

container.bind(Katana).toSelf();
container
.bind<Weapon>('Weapon')
.toResolvedValue((weapon: Weapon): Weapon => weapon, [Katana]);

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

You can also provide more detailed options in order to received resolved services:

const container: Container = new Container();

container.bind(Katana).toSelf().whenNamed('katana');

container.bind<Arsenal>('Arsenal').toResolvedValue(
(weapon: Weapon): Arsenal => ({
weapons: [weapon],
}),
[
{
name: 'katana',
serviceIdentifier: Katana,
},
],
);

const arsenal: Arsenal = container.get('Arsenal');

toService​

toService(service: 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,
);

BindInFluentSyntax​

interface BindInFluentSyntax<T> extends BoundServiceSyntax {
// ...
}

Represents a service binding given a service identifier and a service resolution such as a constructor, a factory, or a provider. Implements BoundServiceSyntax to provide access to the binding's unique identifier.

inSingletonScope​

inSingletonScope(): BindWhenOnFluentSyntax<T>;

Sets the binding scope to singleton. Refer to the docs for more information.

inTransientScope​

inTransientScope(): BindWhenOnFluentSyntax<T>;

Sets the binding scope to transient. Refer to the docs for more information.

inRequestScope​

inRequestScope(): BindWhenOnFluentSyntax<T>;

Sets the binding scope to request. Refer to the docs for more information.

BindOnFluentSyntax​

interface BindOnFluentSyntax<T> extends BoundServiceSyntax {
// ...
}

Allows setting binding activation and deactivation handlers. Implements BoundServiceSyntax to provide access to the binding's unique identifier.

onActivation​

onActivation(activation: BindingActivation<T>): BindWhenFluentSyntax<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: ResolutionContext, 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(deactivation: BindingDeactivation<T>): BindWhenFluentSyntax<T>;

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

warning

Only singleton scoped bindings can have deactivation handlers. If you try to add a deactivation handler to a non-singleton binding, an error will be thrown.

BindWhenFluentSyntax​

interface BindWhenFluentSyntax<T> extends BoundServiceSyntax {
// ...
}

Allows setting binding constraints. Implements BoundServiceSyntax to provide access to the binding's unique identifier.

when​

Sets a constraint for the current binding.

when(
constraint: (metadata: BindingConstraints) => boolean,
): BindOnFluentSyntax<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,
) => (bindingconstraints: BindingConstraints) => boolean =
(name: string) =>
(bindingconstraints: BindingConstraints): boolean =>
bindingconstraints.name === 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.

whenAnyAncestor​

whenAnyAncestor(
constraint: (metadata: BindingConstraints) => boolean,
): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a constraint, any ancestor service matches the given constraint.

whenAnyAncestorIs​

whenAnyAncestorIs(
serviceIdentifier: ServiceIdentifier,
): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a service identifier, any ancestor service was requested with the given identifier.

whenAnyAncestorNamed​

whenAnyAncestorNamed(name: MetadataName): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a name, a named parent service was requested with the given name.

whenAnyAncestorTagged​

whenAnyAncestorTagged(
tag: MetadataTag,
tagValue: unknown,
): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a tag, a tagged parent service was requested with the given tag.

whenDefault​

whenDefault(): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if the service is not requested with any name nor tags.

whenNamed​

Constrains the binding to be used if and only if, given a name, a named service is requested with the given name.

whenNamed(name: MetadataName): BindOnFluentSyntax<T>;

whenNoAncestor​

whenNoAncestor(
constraint: (metadata: BindingConstraints) => boolean,
): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a constraint, no ancestor service matches the given constraint.

whenNoAncestorIs​

whenNoAncestorIs(serviceIdentifier: ServiceIdentifier): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a service identifier, no ancestor service was requested with the given identifier.

whenNoAncestorNamed​

whenNoAncestorNamed(name: MetadataName): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a name, no ancestor service was requested with the given name.

whenNoAncestorTagged​

whenNoAncestorTagged(
tag: MetadataTag,
tagValue: unknown,
): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a tag, no ancestor service was requested with the given tag.

whenNoParent​

whenNoParent(
constraint: (metadata: BindingConstraints) => boolean,
): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a constraint, no parent service matches the given constraint.

whenNoParentIs​

whenNoParentIs(serviceIdentifier: ServiceIdentifier): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a service identifier, no parent service was requested with the given identifier.

whenNoParentNamed​

whenNoParentNamed(name: MetadataName): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a name, no parent service was requested with the given name.

whenNoParentTagged​

whenNoParentTagged(
tag: MetadataTag,
tagValue: unknown,
): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a tag, no parent service was requested with the given tag.

whenParent​

whenParent(
constraint: (metadata: BindingConstraints) => boolean,
): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a constraint, the parent service matches the given constraint.

whenParentIs​

whenParentIs(serviceIdentifier: ServiceIdentifier): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a service identifier, the parent service was requested with the given identifier.

whenParentNamed​

whenParentNamed(name: MetadataName): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a name, the parent service was requested with the given name.

whenParentTagged​

whenParentTagged(tag: MetadataTag, tagValue: unknown): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a tag, the parent service was requested with the given tag.

whenTagged​

whenTagged(tag: MetadataTag, tagValue: unknown): BindOnFluentSyntax<T>;

Constrains the binding to be used if and only if, given a tag, a tagged service is requested with the given tag.

BindWhenOnFluentSyntax​

The union of BindWhenFluentSyntax and BindOnFluentSyntax.

export interface BindWhenOnFluentSyntax<T>
extends BindWhenFluentSyntax<T>,
BindOnFluentSyntax<T> {}

BindInWhenOnFluentSyntax​

The union of BindInFluentSyntax and BindWhenOnFluentSyntax.

export interface BindInWhenOnFluentSyntax<T>
extends BindInFluentSyntax<T>,
BindWhenOnFluentSyntax<T> {}