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.
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.
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> {}