@elsikora/cladi

中文文档
2.1.2发布于 2026/02/22MITTypeScriptESM + CJS零依赖近 30 天下载 1.3万

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

中文使用文档
文档目录38 节
  1. 重点
  2. 目录
  3. 说明
  4. 实际世界使用案例
  5. QQ 技术堆栈
  6. * 特性
  7. 建筑
  8. 系统架构
  9. 数据流动
  10. 项目结构
  11. · 先决条件
  12. * 安装
  13. 开发设置
  14. 测试工具箱
  15. 使用量
  16. 快速启动 — 您的第一个构成根
  17. 请求范围决议
  18. 懒惰提供商( 退化分辨率)
  19. 多键模式
  20. 模块系统
  21. 装饰器模块组成(最像 Ergonomics)
  22. 生命周期钩
  23. 诊断
  24. 锁定、 启动和图导出
  25. API 快速引用
  26. 生产靴子
  27. 常见陷阱
  28. * 路线图
  29. 问 题
  30. ClaDI 需要吗 reflect-metadata 还是实验装饰?
  31. ClaDI如何与倒数JS或tsyringe比较??
  32. 我能在浏览器里使用ClaDI吗?
  33. 我如何处理async初始化(例如数据库连接)?
  34. 如果我忘记处理瞄准镜怎么办?
  35. 我能控制一个在儿童试验场的供应商吗?
  36. 是否需要模块系统?
  37. 许可证
  38. 承认

project-logo

++ ClaDI 数据交换

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

ElsiKora TypeScript Node.js npm Rollup Vitest ESLint Prettier GitHub Actions

重点

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

目录

说明

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

建筑

系统架构

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]

数据流动

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 (用于开发)

* 安装

# Using npm
npm install @elsikora/cladi

# Using yarn
yarn add @elsikora/cladi

# Using pnpm
pnpm add @elsikora/cladi

# Using bun
bun add @elsikora/cladi

开发设置

# 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数字 :

npm install -D @elsikora/cladi @elsikora/cladi-testing
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);

使用量

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

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

请求范围决议

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

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

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

多键模式

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]

模块系统

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)

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 为定制的管弦乐.


生命周期钩

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

诊断

// 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)', ...], ... }

锁定、 启动和图导出

// 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 或关闭流量

生产靴子

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

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()数字 :

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数字 :

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

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

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

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

是否需要模块系统?

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

许可证

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

承认


回到顶部

版本与发布记录

@elsikora/cladi 共发布 16 个版本,首次发布于 2025/04/08;过去 12 个月发布了 7 个版本。

版本发布日期距今
2.1.2latest2026/02/228 个月前
2.1.2-dev.1beta2026/02/228 个月前
2.1.12026/02/228 个月前
2.1.1-dev.22026/02/228 个月前
2.1.1-dev.12026/02/228 个月前
2.1.02026/02/228 个月前

关于 @elsikora/cladi 的常见问题

@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 和提交记录判断。