InversifyJS:强大的 TypeScript IoC 容器
InversifyJS 是一个轻量级但极其强大的 IoC(控制反转)容器,适用于 TypeScript 和 JavaScript 应用。它实现了 依赖注入(DI) 模式,使开发者能够创建低耦合、可测试且可扩展的系统。该库充分利用 TypeScript 的特性(装饰器、类型)来确保严格的类型检查和开发便利性。
InversifyJS 非常适合 Node.js 上的服务器端应用,以及使用 Angular、React 或 Vue 等框架的客户端项目。在本概述中,我们将解析关键概念并展示如何快速上手。
InversifyJS 的核心概念
在编写代码之前,理解该库的三个主要实体很重要:
- 容器(Container) — 管理所有依赖关系的核心对象。您在其中注册抽象及其实现。
- 服务标识符(Service Identifiers) — 容器用来查找相应实现的唯一键。可以是字符串、符号或类。
- 装饰器 —
@injectable()和@inject()— 向 TypeScript 指示该类可以被注入,以及它需要哪些依赖。
安装与配置
首先,安装 InversifyJS 及其类型依赖:
npm install inversify reflect-metadata --savenpm install --save-dev @types/node然后,在 tsconfig.json 中添加两个必需选项:
{ "compilerOptions": { "emitDecoratorMetadata": true, "experimentalDecorators": true, "types": ["reflect-metadata"] }}之后,在应用的主文件(通常是 index.ts 或 main.ts)中导入 reflect-metadata:
import "reflect-metadata";第一个示例:简单服务
创建一个接口及其实现。请注意 @injectable() 装饰器:
// interfaces/IWarrior.tsexport interface IWarrior { fight(): string;}
// entities/Warrior.tsimport { injectable } from "inversify";
@injectable()export class Warrior implements IWarrior { fight(): string { return "Warrior attacks with sword!"; }}现在,在容器中注册此绑定并获取实例:
import { Container } from "inversify";import { IWarrior } from "./interfaces/IWarrior";import { Warrior } from "./entities/Warrior";
const container = new Container();
// 注册抽象及其实现container.bind<IWarrior>("IWarrior").to(Warrior);
// 获取实例const warrior = container.get<IWarrior>("IWarrior");console.log(warrior.fight()); // "Warrior attacks with sword!"通过构造函数注入依赖
当一个类依赖于另一个类时,DI 的真正威力得以展现。使用 @inject() 装饰器:
// interfaces/IWeapon.tsexport interface IWeapon { use(): string;}
// entities/Sword.tsimport { injectable } from "inversify";
@injectable()export class Sword implements IWeapon { use(): string { return "Swing sword!"; }}
// entities/Knight.tsimport { injectable, inject } from "inversify";import { IWarrior } from "../interfaces/IWarrior";import { IWeapon } from "../interfaces/IWeapon";
@injectable()export class Knight implements IWarrior { private _weapon: IWeapon;
constructor(@inject("IWeapon") weapon: IWeapon) { this._weapon = weapon; }
fight(): string { return this._weapon.use() + " The knight fights!"; }}注册