Skip to main content
Version: 7.x

Migrating from v6

InversifyJS v7 introduces several breaking changes. This guide will help you migrate your existing InversifyJS v6 code to v7.

Overview of Changes

The following table summarizes the key changes from v6 to v7:

v6v7Comment
autoBindInjectable optionautobind optionRenamed container constructor option
container.resolve(X)container.get(X, { autobind: true })resolve replaced by get with autobind option
Custom metadata and middlewaresNo direct replacementRemoved to simplify the library and avoid exposing internal data structures
container.isBoundNamedcontainer.isBound(X, { name: ... })Merged all isBound variants with an options parameter
container.isBoundTaggedcontainer.isBound(X, { tag: ... })Merged all isBound variants with an options parameter
container.getNamedcontainer.get(X, { name: ... })Merged all get variants with an options parameter
container.getTaggedcontainer.get(X, { tag: ... })Merged all get variants with an options parameter
container.tryGetcontainer.get(X, { optional: true })Added optional flag for optional get
container.tryGetNamedcontainer.get(X, { name: ..., optional: true })Combined named and optional parameters
container.tryGetTaggedcontainer.get(X, { tag: ..., optional: true })Combined tagged and optional parameters
container.loadawait container.loadNow returns a Promise
container.loadcontainer.loadSyncSynchronous alternative to async load
container.unloadawait container.unloadNow returns a Promise
container.unloadcontainer.unloadSyncSynchronous alternative to async unload
container.rebindawait container.rebind or container.rebindSyncNow async, with a sync alternative
container.unbindawait container.unbind or container.unbindSyncNow async, with a sync alternative
container.createChild()new Container({ parent: container })Child containers created via constructor
interfaces.ContextResolutionContextUpdated context parameter type in the binding API
interfaces.RequestBindingConstraintsUpdated binding constraint parameter type
interfaces.Provider<T>Provider<T>Directly exported, no longer under interfaces namespace
interfaces.Factory<T>Factory<T>Directly exported, no longer under interfaces namespace
interfaces.Newable<T>Newable<T>Directly exported, no longer under interfaces namespace
Implicit injection inheritance@injectFromBase decoratorExplicit inheritance with a decorator
import { interfaces } from "inversify";import { ... } from "inversify7";Removed interfaces namespace, use direct imports

Container API

Autobinding

In v6, autobinding was enabled by passing the autoBindInjectable option to the container constructor. In v7, this option has been renamed to autobind and can be passed either as part of the Container constructor options or Container.get options.

In v6, container.resolve automatically bound the resolved service to the container. In v7, this behavior has been removed. To enable it, pass the autobind option.

export class Katana {
public readonly damage: number = 10;
}

@injectable()
export class Samurai {
public readonly katana: Katana;

constructor(katana: Katana) {
this.katana = katana;
}
}

const container: Container = new Container();

const samurai: Samurai = container.get(Samurai, { autobind: true });

Custom Metadata and Middlewares

This feature has been removed in v7 with no direct replacement. It was not widely used and contributed to the library's complexity. A better API may be introduced in the future.

isBound-like Methods

Methods like Container.isBoundNamed and Container.isBoundTagged have been replaced by Container.isBound with an optional isBoundOptions parameter to handle named and tagged bindings.

Refer to the API documentation for isBound and isCurrentBound for more details.

get-like Methods

The Container.getNamed, Container.getTagged, Container.tryGet, Container.tryGetNamed, and Container.tryGetTagged methods have been replaced by Container.get with an OptionalGetOptions parameter.

Similarly, Container.getAll, Container.getAllAsync, and Container.getAsync now accept a GetOptions object to specify names or tags.

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

const katana: Weapon = container.get<Weapon>('Weapon', { name: 'Katana' });

Additionally, Container.getAll and Container.getAllAsync now enforce binding constraints. For example:

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

const weapons: Weapon[] = container.getAll<Weapon>('Weapon');

In v6, container.getAll returned all bindings matching the service identifier. In v7, it only returns bindings that match both the service identifier and binding constraints.

load and unload Methods

These methods are now asynchronous and return a Promise. Synchronous alternatives, loadSync and unloadSync, are also available.

const warriorsModule: ContainerModule = new ContainerModule(
(options: ContainerModuleLoadOptions) => {
options.bind<Ninja>('Ninja').to(Ninja);
},
);

const weaponsModule: ContainerModule = new ContainerModule(
(options: ContainerModuleLoadOptions) => {
options.bind<Katana>('Weapon').to(Katana).whenNamed('Melee');
options.bind<Shuriken>('Weapon').to(Shuriken).whenNamed('Ranged');
},
);

await container.load(warriorsModule, weaponsModule);

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

rebind Method

The Container.rebind method is now asynchronous and returns a Promise. A synchronous alternative, Container.rebindSync, is also available.

unbind and unbindAll Methods

The Container.unbind method is now asynchronous and returns a Promise. A synchronous alternative, Container.unbindSync, is also available.

Parent and Child Containers

In v6, child containers were created using the createChild method. In v7, this method has been removed. Instead, pass the parent container to the constructor of the child container.

class Katana {}

const parentContainer: Container = new Container();
parentContainer.bind(weaponIdentifier).to(Katana);

const childContainer: Container = new Container({ parent: parentContainer });

const katana: Katana = childContainer.get(weaponIdentifier);

ContainerModule API

Container module load options are now passed as an object.

const warriorsModule: ContainerModule = new ContainerModule(
(options: ContainerModuleLoadOptions) => {
options.bind<Ninja>('Ninja').to(Ninja);
},
);

const weaponsModule: ContainerModule = new ContainerModule(
(options: ContainerModuleLoadOptions) => {
options.bind<Katana>('Weapon').to(Katana).whenNamed('Melee');
options.bind<Shuriken>('Weapon').to(Shuriken).whenNamed('Ranged');
},
);

await container.load(warriorsModule, weaponsModule);

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

BindingFluentSyntax API

ResolutionContext Instead of interfaces.Context

The Context class has been replaced by ResolutionContext to simplify the API and hide internal data structures.

@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;
});

BindingConstraints Instead of interfaces.Request

The Request object has been replaced by BindingConstraints to simplify the API and hide internal data structures.

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;

Decorators API

Inheritance

Injection inheritance is now explicit using the @injectFromBase decorator. This provides more control and avoids edge cases related to constructor argument mismatches.

For more details, refer to the Inheritance documentation.