什么是 TypeScript 的依赖注入容器?
依赖注入 (DI) 是一种设计模式,对象从外部获取其依赖项,而不是自己创建它们。DI 容器是一种自动管理这些依赖项的创建和注入的工具。在 TypeScript 中,由于静态类型检查,DI 容器特别有效:它们保证了类型安全并简化了测试。
容器的主要任务是将接口与其具体实现绑定,并解析依赖链。这允许编写松散耦合、模块化的代码,易于维护和扩展。
为什么在 TypeScript 中需要 DI 容器?
- 减少代码耦合 — 类不依赖于具体实现,只依赖于抽象(接口)。
- 简化测试 — 依赖项可以轻松替换为模拟对象或桩。
- 生命周期管理 — 容器可以创建单例、瞬态对象或具有指定作用域的对象。
- 自动依赖解析 — 容器自行构建依赖树,使开发者免于手动构造对象。
TypeScript 的流行 DI 容器
我们来看两个最常用的库:InversifyJS 和 TSyringe。两者都支持 TypeScript,但方法不同。
1. InversifyJS
InversifyJS 是一个强大的 IoC 容器,使用装饰器。它需要通过 @injectable() 和 @inject() 装饰器显式声明依赖项。适用于具有清晰架构的大型项目。
安装
npm install inversify reflect-metadata --save在 tsconfig.json 文件中,务必启用:
{ "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true }}使用示例
import { Container, injectable, inject } from "inversify";import "reflect-metadata";
// 定义接口和绑定符号interface ILogger { log(message: string): void;}const TYPES = { ILogger: Symbol.for("ILogger"), IUserService: Symbol.for("IUserService"),};
// 日志记录器实现@injectable()class ConsoleLogger implements ILogger { log(message: string): void { console.log(`[LOG]: ${message}`); }}
// 依赖于日志记录器的服务@injectable()class UserService { constructor(@inject(TYPES.ILogger) private logger: ILogger) {}
createUser(name: string): void { this.logger.log(`用户 ${name} 已创建`); }}
// 配置容器const container = new Container();container.bind<ILogger>(TYPES.ILogger).to(ConsoleLogger).inSingletonScope();container.bind<UserService>(TYPES.IUserService).to(UserService);
// 使用const userService = container.get<UserService>(TYPES.IUserService);userService.createUser("阿列克谢");2. TSyringe
TSyringe 是微软开发的轻量级 DI 容器。它使用装饰器并通过构造函数自动解析。非常适合中小型项目。
安装
npm install tsyringe reflect-metadata --savetsconfig.json 的配置与 InversifyJS 类似。
使用示例
import { container, injectable, singleton } from "tsyringe";import "reflect-metadata";
// 将类注册为单例@singleton()class DatabaseConnection { connect(): void { console.log("数据库连接已建立"); }}
// 自动注入依赖的类@injectable()class UserRepository { constructor(private db: DatabaseConnection) {}
save(user