跳到主要内容
版本:Next

从 v6 迁移

InversifyJS v7 引入了一些重大更改。本指南将帮助你将现有的 InversifyJS v6 代码迁移到 v7。

更改概述

下表总结了从 v6 到 v7 的主要更改:

v6v7备注
autoBindInjectable 选项autobind 选项重命名的容器构造函数选项
container.resolve(X)container.get(X, { autobind: true })resolve 被带有 autobind 选项的 get 替换
自定义元数据和中间件无直接替换已删除以简化库并避免暴露内部数据结构
container.isBoundNamedcontainer.isBound(X, { name: ... })合并了所有带有选项参数的 isBound 变体
container.isBoundTaggedcontainer.isBound(X, { tag: ... })合并了所有带有选项参数的 isBound 变体
container.getNamedcontainer.get(X, { name: ... })合并了所有带有选项参数的 get 变体
container.getTaggedcontainer.get(X, { tag: ... })合并了所有带有选项参数的 get 变体
container.tryGetcontainer.get(X, { optional: true })为可选的 get 添加了 optional 标志
container.tryGetNamedcontainer.get(X, { name: ..., optional: true })组合了命名和可选参数
container.tryGetTaggedcontainer.get(X, { tag: ..., optional: true })组合了标记和可选参数
container.loadawait container.load现在返回一个 Promise
container.loadcontainer.loadSync异步 load 的同步替代方案
container.unloadawait container.unload现在返回一个 Promise
container.unloadcontainer.unloadSync异步 unload 的同步替代方案
container.rebindawait container.rebindcontainer.rebindSync现在是异步的,带有同步替代方案
container.unbindawait container.unbindcontainer.unbindSync现在是异步的,带有同步替代方案
container.createChild()new Container({ parent: container })通过构造函数创建的子容器
interfaces.ContextResolutionContext更新了绑定 API 中的上下文参数类型
interfaces.RequestBindingConstraints更新了绑定约束参数类型
interfaces.Provider<T>Provider<T>直接导出,不再在 interfaces 命名空间下
interfaces.Factory<T>Factory<T>直接导出,不再在 interfaces 命名空间下
interfaces.Newable<T>Newable<T>直接导出,不再在 interfaces 命名空间下
隐式注入继承@injectFromBase 装饰器使用装饰器的显式继承
import { interfaces } from "inversify";import { ... } from "inversify";删除了 interfaces 命名空间,使用直接导入

容器 API

自动绑定

在 v6 中,通过将 autoBindInjectable 选项传递给容器构造函数来启用自动绑定。在 v7 中,此选项已重命名为 autobind,并且可以作为 Container 构造函数选项或 Container.get 选项的一部分传递。

在 v6 中,container.resolve 自动将解析的服务绑定到容器。在 v7 中,此行为已被删除。要启用它,请传递 autobind 选项。

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

自定义元数据和中间件

此功能已在 v7 中删除,没有直接替换。它没有被广泛使用,并且增加了库的复杂性。将来可能会引入更好的 API。

类似 isBound 的方法

Container.isBoundNamedContainer.isBoundTagged 这样的方法已被 Container.isBound 替换,带有一个可选的 isBoundOptions 参数来处理命名和标记绑定。

有关更多详细信息,请参阅 isBoundisCurrentBound 的 API 文档。

类似 get 的方法

Container.getNamedContainer.getTaggedContainer.tryGetContainer.tryGetNamedContainer.tryGetTagged 方法已被带有 OptionalGetOptions 参数的 Container.get 替换。

同样,Container.getAllContainer.getAllAsyncContainer.getAsync 现在接受 GetOptions 对象来指定名称或标签。

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

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

此外,Container.getAllContainer.getAllAsync 现在强制执行绑定约束。例如:

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');

在 v6 中,container.getAll 返回与服务标识符匹配的所有绑定。在 v7 中,它仅返回与服务标识符和绑定约束都匹配的绑定。

信息

如果你需要模拟旧行为,可以使用自定义约束来实现。有关更多信息,请参阅此 问题

loadunload 方法

这些方法现在是异步的并返回 Promise。还提供了同步替代方案 loadSyncunloadSync

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 方法

Container.rebind 方法现在是异步的并返回 Promise。还提供了同步替代方案 Container.rebindSync

unbindunbindAll 方法

Container.unbind 方法现在是异步的并返回 Promise。还提供了同步替代方案 Container.unbindSync

父容器和子容器

在 v6 中,使用 createChild 方法创建子容器。在 v7 中,此方法已被删除。相反,将父容器传递给子容器的构造函数。

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

容器模块 API

容器模块加载选项现在作为对象传递。

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 代替 interfaces.Context

Context 类已被 ResolutionContext 替换,以简化 API 并隐藏内部数据结构。

@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 代替 interfaces.Request

Request 对象已被 BindingConstraints 替换,以简化 API 并隐藏内部数据结构。

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;

装饰器 API

继承

注入继承现在使用 @injectFromBase 装饰器显式进行。这提供了更多控制,并避免了与构造函数参数不匹配相关的边缘情况。

有关更多详细信息,请参阅 继承文档