tsyringe TypeScript 依赖注入:完整教程与实战示例
在现代 TypeScript 开发中,依赖管理是构建可扩展、可测试应用的关键任务之一。tsyringe 是一个轻量级且功能强大的依赖注入(Dependency Injection, DI)容器,完全基于 TypeScript 装饰器构建。它允许开发者以声明式方式描述组件间的依赖关系,自动解析这些依赖,并管理对象的生命周期。
为什么需要 tsyringe?在大型项目中,手动创建类实例并将其传递给构造函数会导致代码高度耦合,增加测试难度,并阻碍实现的替换。tsyringe 通过提供一个集中式注册表(容器)来解决这些问题,该容器知道如何创建和提供依赖。你只需指定哪些类或令牌需要注册,容器就会自动将它们注入到需要的地方。这使代码更简洁、更模块化,并大大简化了单元测试的编写。
该库积极使用 TypeScript 装饰器(@injectable()、@inject()),使得熟悉 Angular 或 NestJS 的开发者能够直观理解其语法。tsyringe 无需复杂配置,开箱即用,支持现代 TypeScript 版本,并提供多种注册策略(singleton、transient、scoped)。本文将详细解析 tsyringe 的各个方面,从安装到高级使用场景。
安装
要在你的 TypeScript 项目中安装 tsyringe,请使用 npm 执行以下命令:
npm install tsyringe reflect-metadata
安装后,需要确保项目已配置装饰器支持。为此,在 tsconfig.json 文件中启用以下选项:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
此外,在应用的入口点(例如 index.ts)中,需要一次性导入 reflect-metadata 以启用装饰器的元数据:
import "reflect-metadata";
// ... 其余代码
快速上手:最小化工作示例
让我们创建一个简单的应用,演示 tsyringe 的基本机制。我们将有一个数据库服务,它被注入到控制器中。
import "reflect-metadata";
import { container, injectable, inject } from "tsyringe";
// 1. 定义将被注入的服务
@injectable()
class DatabaseService {
getData(): string {
return "来自数据库的数据";
}
}
// 2. 定义依赖于 DatabaseService 的控制器
@injectable()
class UserController {
constructor(
@inject(DatabaseService) private dbService: DatabaseService
) {}
getUserData(): string {
return this.dbService.getData();
}
}
// 3. 在容器中注册类(此处非必需,因为 tsyringe 可自动解析已注册的类)
container.registerSingleton(DatabaseService);
container.registerSingleton(UserController);
// 4. 使用容器获取控制器实例
const controller = container.resolve(UserController);
console.log(controller.getUserData()); // 输出:"来自数据库的数据"
此示例展示了三个关键步骤:将类标记为 @injectable(),通过构造函数中的 @inject() 指定依赖,以及通过 container.resolve() 获取实例。请注意,如果类已通过装饰器注册,则无需显式调用 registerSingleton。