# @elsikora/cladi 中文文档

规范地址：https://npmcn.com/package/%40elsikora/cladi/

版本：2\.1\.2
npm 元数据更新时间：2026-02-21T23:07:03.477Z
中文译文更新时间：2026-11-13T14:08:36.633Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40elsikora/cladi
原文对照：https://npmcn.com/package/%40elsikora/cladi/?lang=original
项目主页：https://github.com/ElsiKora/ClaDI#readme
源码仓库：https://github.com/ElsiKora/ClaDI

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：900 kB，621 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=20
- 运行依赖：0 个
- 首次发布：2025-04-07T23:34:25.725Z
- 最新版本发布：2026-02-21T23:07:03.300Z
- 近 30 天下载量：13261（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：16（近 12 个月 7 个）

## 中文简介

零依赖性 TypeScript DI 工具包有打字符和范围化生命周期.

## 安装

```sh
npm install @elsikora/cladi
```

也可以使用：`pnpm add @elsikora/cladi`、`yarn add @elsikora/cladi`、`bun add @elsikora/cladi`

## README

![project-logo](https://6jft62zmy9nx2oea.public.blob.vercel-storage.com/cladi-eBDDJPOc5fj21RO45PzAwrdkkqGCHi.png)

# ++ ClaDI 数据交换

_零依赖性类型Script依赖性注射工具包,用于组分-根基架构和清洁的模块化应用程序_

 [![ElsiKora](https://img.shields.io/badge/MADE%20BY%20ElsiKora-333333.svg?style=for-the-badge)](https://elsikora.com/)![TypeScript](https://img.shields.io/badge/TypeScript-3178C6.svg?style=for-the-badge&logo=typescript&logoColor=white) ![Node.js](https://img.shields.io/badge/Node.js-339933.svg?style=for-the-badge&logo=node.js&logoColor=white) ![npm](https://img.shields.io/badge/npm-CB3837.svg?style=for-the-badge&logo=npm&logoColor=white) ![Rollup](https://img.shields.io/badge/Rollup-EC4A3F.svg?style=for-the-badge&logo=rollup&logoColor=white) ![Vitest](https://img.shields.io/badge/Vitest-6E9F18.svg?style=for-the-badge&logo=vitest&logoColor=white) ![ESLint](https://img.shields.io/badge/ESLint-4B32C3.svg?style=for-the-badge&logo=eslint&logoColor=white) ![Prettier](https://img.shields.io/badge/Prettier-F7B93E.svg?style=for-the-badge&logo=prettier&logoColor=black) ![GitHub Actions](https://img.shields.io/badge/GitHub%20Actions-2088FF.svg?style=for-the-badge&logo=github-actions&logoColor=white)

## 重点

-   零运行时间依赖性——以最低捆绑成本、无过渡性依赖性风险的全DI集装箱船
-   完全类型安全标志通过 `createToken<T>()` ——依赖错配在编译时被捕获,而不是运行时
-   \* 具有确定性处置作用的范围-认识生命周期——单吨、范围、以及按正确顺序自动清理的瞬态供应商
-   • 清洁建筑土生土长——域和应用层从未导入 DI API;只有成分根会触碰容器

## 目录

-   [说明](https://npmcn.com/package/%40elsikora/cladi/#readme--description)
-   [技术堆栈](https://npmcn.com/package/%40elsikora/cladi/#readme--tech-stack)
-   [特征](https://npmcn.com/package/%40elsikora/cladi/#readme--features)
-   [建筑](https://npmcn.com/package/%40elsikora/cladi/#readme--architecture)
-   [项目结构](https://npmcn.com/package/%40elsikora/cladi/#readme--project-structure)
-   [先决条件](https://npmcn.com/package/%40elsikora/cladi/#readme--prerequisites)
-   [安装](https://npmcn.com/package/%40elsikora/cladi/#readme--installation)
-   [测试工具箱](https://npmcn.com/package/%40elsikora/cladi/#readme--testing-toolkit)
-   [使用量](https://npmcn.com/package/%40elsikora/cladi/#readme--usage)
-   [API 快速引用](https://npmcn.com/package/%40elsikora/cladi/#readme--api-quick-reference)
-   [生产靴子](https://npmcn.com/package/%40elsikora/cladi/#readme--production-bootstrap)
-   [常见陷阱](https://npmcn.com/package/%40elsikora/cladi/#readme--common-pitfalls)
-   [路线图](https://npmcn.com/package/%40elsikora/cladi/#readme--roadmap)
-   [财务问题](https://npmcn.com/package/%40elsikora/cladi/#readme--faq)
-   [许可证](https://npmcn.com/package/%40elsikora/cladi/#readme--license)
-   [承认](https://npmcn.com/package/%40elsikora/cladi/#readme--acknowledgments)

## 说明

ClaDI (Class Dependency Injection)是一个生产级的零依赖性TypeScript库,提供完整的依赖性注射容器,并带有瞄准镜感知寿命周期,打字符,并具有决定性的清理.

与依赖装饰器,反射元数据或跑时魔法的重量级DI框架不同,ClaDI拥抱 **明确的构成根源** 完全控制你的依赖图是如何组装、解决和处理的.

### 实际世界使用案例

-   **后端服务**:连接HTTP处理器,数据库连接,以及带有请求范围隔离的中间软件. 每一个收到的请求都通过自动清理获得自己的范围.
-   **CLI 工具**: 解析参数,将其登记为范围值,解析命令处理器,执行后清理处理.
-   **微服务**: 管理单通适配器(数据库池,消息队列),同时管理每个工作的有生命周期保障的瞬间工.
-   **模块单体**: 使用模块系统(`composeModules`(b) 界定有明确出口合同的有限度的情况——不意外地跨界结合.
-   **测试**:在任何范围级别上将任何提供者交换,而不触及生产代码。 输入的令牌系统在编译时捕获错配 .

CLADI号船舶 **5项提供者战略** (单位:千美元)`useValue`, (中文(简体) ), `useClass`, (中文(简体) ), `useFactory`, (中文(简体) ), `useExisting`, (中文(简体) ), `useLazy`, (中文(简体) ), **3个生命周期模式** (单位:千美元)`singleton`, (中文(简体) ), `scoped`, (中文(简体) ), `transient`),内置 **循环依赖检测**, (中文(简体) ), **依赖性警告**,并满 **同步分辨率** 支持 — 全部在一个零运行时间依赖的软件包中.

## QQ 技术堆栈

| 类别 | 技术 |
| --- | --- |
| **语言** | 类型脚本 |
| **运行时间** | 节点.js |
| **构建工具** | 滚动 |
| **测试** | 维特 |
| **线性** | ESLint, 高级 |
| **排雷中心/发改委** | GitHub 动作,语义释放 |
| **软件包管理器** | 无 |
| **文档** | MDX, Nextra 数据 |

## \* 特性

-   ✨ **键入系统** —— 说 `createToken<T>()` 在整个解析链中产生带类型信息的品牌符号,去除 `any` 投影和运行时间类型出错
-   ✨ **5 提供者战略** —— 说 `useValue`, (中文(简体) ), `useClass`, (中文(简体) ), `useFactory`, (中文(简体) ), `useExisting` (别名)和 `useLazy` (延迟合成)覆盖共同的依赖线布线模式
-   ✨ **范围- 了解寿命周期** - Singleton(全过程),范围(按要求/工作),以及具有确定缓存语义的Transient(按要求/工作)
-   ✨ **等级范围树** ——儿童范围继承父母登记,可以增加本地覆盖,独立处置而不影响兄弟姐妹
-   ✨ **自动解析管道** —— 说 `resolveAsync()` 处理合成工厂,同时减少单吨生成,以及在处置过程中跟踪飞行中分辨率
-   ✨ **生命周期钩** —— 说 `onInit`, (中文(简体) ), `afterResolve`,以及 `onDispose` 供暖、仪器和清洁用的每个供应商的钩子
-   ✨ **多键支持** - 登记多项执行,以示一致,并解决所有问题 `resolveAll()` 编号 : `resolveAllAsync()`
-   ✨ **循环依赖检测** - 在决议通过时发现并主动通过 `validate()` 启动时
-   ✨ **能力依赖警卫** ——单通捕捉范围依赖时警告或出错,可防止微妙的生命周期错误
-   ✨ **模块系统** —— 说 `createModule()` 财务报告和审定财务报表 `composeModules()` 使申报的、有限度的、带有明确出口合同的模块构成成为可能
-   ✨ **装饰者支持** - 可选 `@Injectable()`, (中文(简体) ), `@Inject()`, (中文(简体) ), `@Module()`, (中文(简体) ), `@OnInit()`, (中文(简体) ), `@AfterResolve()`,以及 `@OnDispose()` 无需 `reflect-metadata`
-   ✨ **装饰者** —— 说 `autowire()`, (中文(简体) ), `createModuleFromDecorator()`,以及 `composeDecoratedModules()` 保持装饰工作流程清晰但简洁
-   ✨ **配套测试工具箱** —— 说 `@elsikora/cladi-testing` 增加测试容器辅助器(`createTestingContainer`, (中文(简体) ), `mockProvider`, (中文(简体) ), `overrideProvider`用于应用一级整合和单位测试
-   ✨ **运行时间诊断** —— 说 `explain(token)`, (中文(简体) ), `snapshot()`,以及 `exportGraph()` 向供应商查询和依赖边缘提供业务可见度
-   ✨ **决定处置** —— 说 `dispose()` 等待飞行中的同步分辨率,按倒序运行处置器,并支持 `Symbol.dispose` 编号 : `Symbol.asyncDispose`
-   ✨ **解决拦截者** - 加入每个决议 `onStart`, (中文(简体) ), `onSuccess`,以及 `onError` 记录、衡量或追踪的回调
-   ✨ **安全的深克隆工具** —— 说 `safeDeepClone()` 处理循环引用、函数、映射、设置和类例,不同于 `structuredClone`

## 建筑

### 系统架构

```mermaid
flowchart TD
    presentation[Presentation Layer]
    application[Application Layer]
    domain[Domain Layer]
    infrastructure[Infrastructure Layer]

    presentation --> application
    presentation --> infrastructure
    application --> domain
    infrastructure --> domain

    presentation --- ergonomics[Ergonomics]
    presentation --- utilities[Create Utilities]
    ergonomics --- decorators[Decorators]
    ergonomics --- modules[Module Composer]

    infrastructure --- diContainer[DI Container]
    infrastructure --- coreFactory[Core Factory]
    infrastructure --- loggerService[Console Logger]

    diContainer --- cacheCoord[Cache Coordinator]
    diContainer --- resolutionEngine[Resolution Engine]
    diContainer --- registrationCoord[Registration Coordinator]
    diContainer --- disposalCoord[Disposal Coordinator]

    domain --- tokens[Tokens and Types]
    domain --- enums[Enums]
    domain --- interfaces[Contracts]
```

### 数据流动

```mermaid
sequenceDiagram
    participant App as Application
    participant Container as DI Container
    participant Registry as Registration Coordinator
    participant Engine as Resolution Engine
    participant Cache as Cache Coordinator
    participant Disposal as Disposal Coordinator

    App->>Container: createDIContainer(options)
    App->>Container: register(provider)
    Container->>Registry: registerProvider(provider)
    Registry->>Registry: validate provider shape
    Registry->>Container: store registration

    App->>Container: validate()
    Container->>Container: walk dependency graph

    App->>Container: resolve(token)
    Container->>Engine: resolve(tokenSymbol)
    Engine->>Container: findProvider(scope, key)
    Container->>Cache: getScopedCacheForLifecycle()
    alt Cache Hit
        Cache-->>Engine: cached instance
    else Cache Miss
        Engine->>Engine: instantiate provider
        Engine->>Engine: run onInit hook
        Engine->>Cache: store in cache
        Engine->>Disposal: register disposer
    end
    Engine->>Engine: run afterResolve hook
    Engine-->>App: resolved instance

    App->>Container: dispose()
    Container->>Disposal: disposeInternal()
    Disposal->>Disposal: wait for in-flight async
    Disposal->>Disposal: dispose child scopes
    Disposal->>Disposal: run disposers in reverse
    Disposal->>Cache: clear all caches
```

## 项目结构

单击以扩展

```
ClaDI/
├── .github/
│   ├── workflows/
│   │   ├── mirror-docs-to-docviewer.yml
│   │   ├── mirror-to-codecommit.yml
│   │   ├── qodana-quality-scan.yml
│   │   ├── release.yml
│   │   ├── snyk-security-scan.yml
│   │   └── test.yml
│   └── dependabot.yml
├── docs/
│   ├── api-reference/
│   │   ├── enums/
│   │   ├── interfaces/
│   │   ├── _meta.js
│   │   └── page.mdx
│   ├── core-concepts/
│   │   ├── advanced-di/
│   │   ├── clean-architecture-playbook/
│   │   ├── container/
│   │   ├── error-handling/
│   │   ├── factory/
│   │   ├── registry/
│   │   ├── _meta.js
│   │   └── page.mdx
│   ├── getting-started/
│   │   ├── _meta.js
│   │   ├── composition-root-checklist.mdx
│   │   └── page.mdx
│   ├── services/
│   │   ├── logging/
│   │   ├── _meta.js
│   │   └── page.mdx
│   ├── utilities/
│   │   ├── creation-helpers/
│   │   ├── _meta.js
│   │   └── page.mdx
│   ├── _meta.js
│   └── page.mdx
├── src/
│   ├── application/
│   │   └── utility/
│   ├── domain/
│   │   ├── enum/
│   │   ├── interface/
│   │   ├── type/
│   │   └── index.ts
│   ├── infrastructure/
│   │   ├── class/
│   │   ├── constant/
│   │   ├── factory/
│   │   ├── interface/
│   │   ├── service/
│   │   └── index.ts
│   ├── presentation/
│   │   ├── ergonomics/
│   │   └── utility/
│   └── index.ts
├── test/
│   ├── contract/
│   │   └── di-container.contract.test.ts
│   ├── e2e/
│   │   └── core-integration.e2e.test.ts
│   ├── perf/
│   │   └── di-container.perf.test.ts
│   └── unit/
│       ├── application/
│       ├── ergonomics/
│       ├── infrastructure/
│       └── presentation/
├── CHANGELOG.md
├── commitlint.config.js
├── eslint.config.js
├── LICENSE
├── lint-staged.config.js
├── package-lock.json
├── package.json
├── prettier.config.js
├── release.config.js
├── rollup.config.js
├── rollup.test.config.js
├── tsconfig.build.json
├── tsconfig.json
├── vitest.e2e.config.js
└── vitest.unit.config.js
```

## · 先决条件

-   节点.js >= 20.0.0
-   npm >= 9.0.0
-   TypeScript QQ 5.0.0 (用于开发)

## \* 安装

```bash
# Using npm
npm install @elsikora/cladi

# Using yarn
yarn add @elsikora/cladi

# Using pnpm
pnpm add @elsikora/cladi

# Using bun
bun add @elsikora/cladi
```

### 开发设置

```bash
# Clone the repository
git clone https://github.com/ElsiKora/ClaDI.git
cd ClaDI

# Install dependencies
npm install

# Build the project (ESM + CJS dual output)
npm run build

# Run all tests
npm run test:all

# Run linting
npm run lint:all
```

## 测试工具箱

应用测试时,请使用配套软件包 `@elsikora/cladi-testing` 与 ClaDI 连接 `>=2.1.0`数字 :

```bash
npm install -D @elsikora/cladi @elsikora/cladi-testing
```

```typescript
import { createModule, createToken } from "@elsikora/cladi";
import { createTestingContainer, mockProvider, overrideProvider, resetTestingContainer } from "@elsikora/cladi-testing";

const UserRepoToken = createToken<{ findNameById(id: string): string | undefined }>("UserRepo");
const UserServiceToken = createToken<{ readName(id: string): string }>("UserService");

const appModule = createModule({
    exports: [UserServiceToken],
    providers: [
        mockProvider(UserRepoToken, { findNameById: () => "Alice" }),
        {
            deps: [UserRepoToken],
            provide: UserServiceToken,
            useFactory: (repository) => ({
                readName: (id: string): string => repository.findNameById(id) ?? "unknown",
            }),
        },
    ],
});

const container = createTestingContainer({ modules: [appModule], shouldValidateOnCreate: true });
await overrideProvider(container, mockProvider(UserRepoToken, { findNameById: () => "Bob" }));
await resetTestingContainer(container);
```

## 使用量

### 快速启动 — 您的第一个构成根

```typescript
import { createDIContainer, createToken, EDependencyLifecycle } from "@elsikora/cladi";

// 1. Define typed tokens
const ConfigToken = createToken<{ apiUrl: string }>("Config");
const HttpClientToken = createToken<{ get(path: string): Promise<unknown> }>("HttpClient");

// 2. Create the container
const container = createDIContainer({ scopeName: "root" });

// 3. Register providers
container.register({
    provide: ConfigToken,
    useValue: { apiUrl: "https://api.example.com" },
});

container.register({
    provide: HttpClientToken,
    lifecycle: EDependencyLifecycle.SCOPED,
    deps: [ConfigToken],
    useFactory: (config) => ({
        get: async (path: string) => fetch(`${config.apiUrl}${path}`).then((r) => r.json()),
    }),
});

// 4. Validate at startup
container.validate();

// 5. Resolve dependencies
const http = container.resolve(HttpClientToken);
```

* * *

### 请求范围决议

```typescript
async function handleRequest(requestId: string) {
    const scope = container.createScope("request");

    try {
        // Register request-specific context
        const RequestIdToken = createToken<string>("RequestId");
        scope.register({ provide: RequestIdToken, useValue: requestId });

        // Resolve scoped services
        const http = scope.resolve(HttpClientToken);
        return await http.get("/data");
    } finally {
        // Always dispose the scope
        await scope.dispose();
    }
}
```

* * *

### 懒惰提供商( 退化分辨率)

```typescript
import { createLazyProvider, createToken } from "@elsikora/cladi";

const DbToken = createToken<Database>("Database");
const LazyDbToken = createToken<() => Promise<Database>>("LazyDatabase");

container.register({
    provide: DbToken,
    lifecycle: EDependencyLifecycle.SINGLETON,
    useFactory: async () => await connectToDatabase(),
});

// Lazy provider defers resolution until invoked
container.register(createLazyProvider(LazyDbToken, DbToken));

// Database connection is NOT created yet
const getDb = container.resolve(LazyDbToken);

// Now it resolves
const db = await getDb();
```

* * *

### 多键模式

```typescript
const MiddlewareToken = createToken<Middleware>("Middleware");

container.register({
    provide: MiddlewareToken,
    isMultiBinding: true,
    useFactory: () => createAuthMiddleware(),
});

container.register({
    provide: MiddlewareToken,
    isMultiBinding: true,
    useFactory: () => createLoggingMiddleware(),
});

// Resolve all implementations
const middlewares = container.resolveAll(MiddlewareToken);
// => [authMiddleware, loggingMiddleware]
```

* * *

### 模块系统

```typescript
import { createModule, composeModules, createDIContainer } from "@elsikora/cladi";

const databaseModule = createModule({
    name: "database",
    exports: [DbConnectionToken],
    providers: [
        { provide: DbConfigToken, useValue: { host: "localhost" } },
        {
            provide: DbConnectionToken,
            deps: [DbConfigToken],
            lifecycle: EDependencyLifecycle.SINGLETON,
            useFactory: (config) => createConnection(config),
        },
    ],
});

const appModule = createModule({
    name: "app",
    imports: [databaseModule],
    providers: [
        {
            provide: UserRepoToken,
            deps: [DbConnectionToken],
            useFactory: (db) => new UserRepository(db),
        },
    ],
});

const container = createDIContainer();
composeModules(container, [appModule]);
```

* * *

### 装饰器模块组成(最像 Ergonomics)

```typescript
import { Inject, Injectable, Module, composeDecoratedModules, createDIContainer, createToken, EDependencyLifecycle } from "@elsikora/cladi";

const ConfigToken = createToken<{ baseUrl: string }>("Config");
const ApiToken = createToken<{ ping(): string }>("Api");

@Injectable({ token: ApiToken, lifecycle: EDependencyLifecycle.SINGLETON })
class ApiService {
    constructor(@Inject(ConfigToken) private readonly config: { baseUrl: string }) {}

    public ping(): string {
        return `pong:${this.config.baseUrl}`;
    }
}

@Module({
    exports: [ApiToken],
    providers: [{ provide: ConfigToken, useValue: { baseUrl: "https://api.example.com" } }, ApiService],
})
class AppModule {}

const container = createDIContainer();
composeDecoratedModules(container, [AppModule]);
```

使用 `createModuleFromDecorator()` 需要手动转换为平原时直接 `IDIModule` 为定制的管弦乐.

* * *

### 生命周期钩

```typescript
container.register({
    provide: CacheToken,
    lifecycle: EDependencyLifecycle.SINGLETON,
    useFactory: () => new RedisCache(),
    onInit: (cache) => cache.warmup(),
    afterResolve: (cache) => cache.recordUsage(),
    onDispose: async (cache) => await cache.disconnect(),
});
```

* * *

### 诊断

```typescript
// Explain resolution path for a token
const explanation = container.explain(HttpClientToken);
console.log(explanation);
// { isFound: true, lifecycle: 'scoped', providerType: 'factory',
//   dependencies: ['Symbol(Config)'], lookupPath: ['root'], ... }

// Full container snapshot
const snapshot = container.snapshot();
console.log(snapshot);
// { scopeId: 'root', providerCount: 3, singletonCacheSize: 1,
//   tokens: ['Symbol(Config)', 'Symbol(HttpClient)', ...], ... }
```

* * *

### 锁定、 启动和图导出

```typescript
// Eagerly initialize singleton providers (and run onInit hooks)
await container.bootstrap();

// Optionally bootstrap specific tokens only
await container.bootstrap([DbToken, CacheToken]);

// Freeze registration surface for runtime safety
container.lock();
console.log(container.isLocked); // true

// Export graph for observability or visualization
const graph = container.exportGraph();
console.log(graph.nodes);
console.log(graph.edges);
```

## API 快速引用

目标 API 注解 |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - - - - - - -- - - - - - -- - - -- - - - - - - - - - -- - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 解决一个依赖(同步) `resolve(token)` QQ 如果提供者路径是 async 将丢入 QQ 解决一个依赖(同步) `resolveAsync(token)` 与Aync工厂和Aync钩合作 解决许多执行问题 `resolveAll(token)` 编号 : `resolveAllAsync(token)` \* 用于多约束性登记 解决可选依赖性 `resolveOptional(token)` 编号 : `resolveOptionalAsync(token)` | 归来 `undefined` 如果没有找到 qq QQ 创建孤立的运行时间边界QQ `createScope(name?)` 用于请求/工作/命令上下文 登记提供者 {} `register(provider | provider[])` ++ 支持所有提供者战略 ++ 启动时验证图 `validate()` 检查缺少的道具、周期和政策规则 \* 温暖前单子图 `bootstrap(tokens?)` ++ Eager 分辨率 + `onInit` 执行 锁定运行时的注册表面 `lock()` 编号 : `isLocked` 预防 `register` 编号 : `unregister` 电话qq 检查运行时间路径并缓存 {} `explain(token)` 编号 : `snapshot()` QQ 调试搜索路径和缓存状态 导出依赖节点和边缘 `exportGraph()` 诊断和工具结构图 \* \* \* \* 组成普通模块\* \* \* \* \* `composeModules(container, modules)` | `IDIModule` 进出口合同 · 编写装饰的模块类 `composeDecoratedModules(container, modules)` \\\\\\ 接受\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ `@Module` 课程和普通模块 释放资源 `scope.dispose()` 编号 : `container.dispose()` 总是打电话来 `finally` 或关闭流量

## 生产靴子

使用明确的政策和优雅的关闭 :

```typescript
import { createDIContainer, EDiContainerCaptiveDependencyPolicy, EDiContainerDuplicateProviderPolicy, type IResolveInterceptor } from "@elsikora/cladi";

const metricsInterceptor: IResolveInterceptor = {
    onError: ({ tokenDescription, error }) => {
        console.error("resolve error", tokenDescription, error.message);
    },
    onStart: ({ tokenDescription }) => {
        console.debug("resolve start", tokenDescription);
    },
    onSuccess: ({ tokenDescription }) => {
        console.debug("resolve success", tokenDescription);
    },
};

const container = createDIContainer({
    captiveDependencyPolicy: EDiContainerCaptiveDependencyPolicy.ERROR,
    duplicateProviderPolicy: EDiContainerDuplicateProviderPolicy.ERROR,
    resolveInterceptors: [metricsInterceptor],
    scopeName: "root",
});

// register providers...
container.validate();

const shutdown = async (): Promise<void> => {
    await container.dispose();
};

process.once("SIGINT", () => {
    void shutdown();
});

process.once("SIGTERM", () => {
    void shutdown();
});
```

## 常见陷阱

-   使用 `resolve()` 用于Aync提供者或Aync钩. 使用 `resolveAsync()` 为了那些纪念物.
-   登记多约束性供应商和电话 `resolve()` 改为 `resolveAll()` 编号 : `resolveAllAsync()`。 。 。 .
-   跳过 `validate()` 启动时和仅在运行时查找图表问题.
-   忘记 `scope.dispose()` 造成范围被泄露的资源.
-   按需要处理可选依赖关系. 使用 `resolveOptional()` 对于真正可选的合同.

## \* 路线图

单击以扩展

| 任务/ 特性 | 状态 |
| --- | --- |
| 带有打字符的核心 DI 容器 | 完毕 |
| 单子、范围及瞬变寿命周期 | 完毕 |
| 用分解来解析 | 完毕 |
| 懒惰提供者战略`useLazy`(中文(简体) ) | 完毕 |
| 多种约束性支持`resolveAll`(中文(简体) ) | 完毕 |
| 模块组成系统(`composeModules`(中文(简体) ) | 完毕 |
| 寿命周期钩(在Init上,在Resolve后,在处置上) | 完毕 |
| 循环依赖检测和验证 | 完毕 |
| 附带依赖政策(警告/错误/残疾) | 完毕 |
| 为可观察性解析拦截器 | 完毕 |
| 设计师制`@Injectable`, (中文(简体) ), `@Inject`(中文(简体) ) | 完毕 |
| 安全深层克隆工具 | 完毕 |
| 与 MDX 的综合文件 | 完毕 |
| 具有同源排出物的分级范围处置 | 完毕 |
| 标记/有条件提供者解析 | 执行中 |
| 供应商中间软件管道 | 执行中 |
| 生命周期活动的范围级活动发射装置 | 执行中 |
| 业绩基准套件 | 执行中 |

## 问 题

单击以扩展

### ClaDI 需要吗 `reflect-metadata` 还是实验装饰?

没有。 ClaDI工作完全没有反射元数据. 可选装饰者`@Injectable`, (中文(简体) ), `@Inject`, (中文(简体) ), `@Module`, (中文(简体) ), `@OnInit`, (中文(简体) ), `@AfterResolve`, (中文(简体) ), `@OnDispose`) 直接将元数据存储在使用符号键的类构造器/原型上 — no `reflect-metadata` 需要多填充剂。 您也可以完全跳过装饰器并使用简单的提供者, `createAutowireProvider()`,以及 `createModule()`。 。 。 .

### ClaDI如何与倒数JS或tsyringe比较??

CLADI采取完全不同的方法: **明确的构成根源** 超过隐形装饰器驱动的接线。 没有全球容器,没有自动类扫描,也没有隐藏的元数据. 在登记地点可以看到每一种依赖关系。 这使得DI图可以审计,可以测试,并且便于再造.

### 我能在浏览器里使用ClaDI吗?

ClaDI 船舶无害环境管理和CJS捆绑,设计为运行时不可知. 在Node.js测试。 Bun, Deno, 和浏览器的用法一般是可行的, 当你的环境支持您的提供者所使用的标准 JavaScript 运行时特性时.

### 我如何处理async初始化(例如数据库连接)?

使用 `useFactory` 带有同步函数,并与 `resolveAsync()`数字 :

```typescript
container.register({
    provide: DbToken,
    lifecycle: EDependencyLifecycle.SINGLETON,
    useFactory: async () => await createDatabasePool(),
    onDispose: async (pool) => await pool.end(),
});

const db = await container.resolveAsync(DbToken);
```

同时 `resolveAsync()` 同一单通的呼号自动被去除——工厂运行精确一次.

### 如果我忘记处理瞄准镜怎么办?

范围化和单子化实例 `onDispose` 钩子或 `dispose()` 编号 : `close()` 方法不会被清理,可能造成资源泄漏。 总是将范围用法包入 `try/finally`数字 :

```typescript
const scope = container.createScope("request");
try {
    // ... use scope
} finally {
    await scope.dispose();
}
```

### 我能控制一个在儿童试验场的供应商吗?

当然 儿童范围可以注册本地覆盖, 阴影父母注册:

```typescript
const testScope = container.createScope("test");
testScope.register({ provide: DbToken, useValue: mockDatabase });
const service = testScope.resolve(ServiceToken); // uses mockDatabase
```

### 是否需要模块系统?

没有 模块系统`createModule` 编号 : `composeModules`)是完全可选的。 您可以直接在容器上注册所有提供者。 模块有助于将大型应用组织到有明确出口界限的有界限的背景中.

## 许可证

这个项目的许可证根据 **麻省理工学院**。 。 。 .

## 承认

-   建造和维护 [埃尔西科拉](https://github.com/ElsiKora)
-   受来自Angular、NestJS和InversifyJS的依赖性注射模式的启发——适应明确的成分-根干流程
-   谢谢大家 [捐助者](https://github.com/ElsiKora/ClaDI/graphs/contributors) 帮助构建 API 和测试套件
-   提供的文件 [下一个](https://nextra.site/) 带有 MDX
-   通过 [语义释放](https://github.com/semantic-release/semantic-release)
-   代码质量由 [加纳](https://www.jetbrains.com/qodana/) 财务报告和审定财务报表 [斯奈克语Name](https://snyk.io/)

* * *

[回到顶部](https://npmcn.com/package/%40elsikora/cladi/#readme-top)

## 常见问题

### @elsikora/cladi 是什么？

零依赖性 TypeScript DI 工具包有打字符和范围化生命周期\.

### 如何安装 @elsikora/cladi？

在项目目录运行 npm install @elsikora/cladi，或使用 pnpm add / yarn add / bun add。

### @elsikora/cladi 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @elsikora/cladi 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @elsikora/cladi 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @elsikora/cladi 可以商用吗？

@elsikora/cladi 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @elsikora/cladi 的下载量有多少？

根据 npm 官方下载统计，@elsikora/cladi 在 2026/10/14 – 2026/11/12 这 30 天内被下载 13,261 次，日均约 442 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @elsikora/cladi 还在维护吗？

最新版本 2\.1\.2 发布于 2026/02/22（8 个月前）；至今共发布 16 个版本，其中过去 12 个月发布了 7 个；首次发布于 2025/04/08。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

