@di-framework/core

中文文档
6.1.0发布于 2026/10/12(MIT OR Apache-2.0)TypeScriptES Module零依赖构建来源已验证近 30 天下载 4535

轻量级,零依赖型的TypeScript依赖注射框架使用装饰. 与SWC和TypeScript的本土装饰器支持无缝地工作.

中文使用文档
文档目录40 节
  1. 明确的应用程序启动
  2. 安装
  3. 快速启动
  4. 1. 基本服务
  5. 2. 向受抚养人提供服务
  6. 3. 解决服务
  7. API 参考
  8. @Container(options?)
  9. @Component(target)
  10. @Telemetry(options?)
  11. @TelemetryListener()
  12. useContainer()
  13. container.register(serviceClass, options?)
  14. container.registerFactory(name, factory, options?)
  15. container.resolve(serviceClass)
  16. container.has(serviceClass)
  17. container.getServiceNames()
  18. container.on(event, listener)
  19. container.construct(serviceClass, overrides?)
  20. container.fork(options?)
  21. 高级示例
  22. 多重依赖
  23. 临时(非英语)服务
  24. 生命周期方法
  25. 工厂功能
  26. 如何运作
  27. 与 SAMPLE.ts 的比较
  28. 之前( 手册- SAMPLE. ts)
  29. 之后( DI 框架)
  30. 处理错误
  31. 循环依赖
  32. 未登记的服务
  33. 最佳做法
  34. 测试
  35. 许可证
  36. 私营服务对服务的约束
  37. 1. 申报出口服务
  38. 2. 向打电话者发送装订服务
  39. 3. 拒绝不受约束的打电话者
  40. 4. 地方多服务发展和移动替代

@ di- framework/ core (简体中文)

CI npm version license

使用装饰器的TypeScript轻量级,型号安全的依赖注射框架. 这个框架自动管理服务即时化,依赖性解析和生命周期管理.

明确的应用程序启动

使用 @Configuration() 财务报告和审定财务报表 @Bean() 用于工厂接线。 依赖是: 明确列出,因此启动检测缺失、重复和循环豆 在援引工厂之前 阿辛克工厂在等待着 Container.resolve() 保持同步状态.

import { ApplicationContext } from '@di-framework/core/application-context';
import { Bean, Configuration } from '@di-framework/core/decorators';

@Configuration()
class AppConfiguration {
  @Bean()
  port() { return 8080; } // token defaults to "port"

  @Bean('serverUrl', { dependencies: ['port'] })
  async serverUrl(port: number) { return `http://localhost:${port}`; }
}

const app = ApplicationContext.builder()
  .configuration(AppConfiguration)
  .bootstrap(HttpServer)
await app.start();
await app.stop();

靴子组件可能定义同步或同步 start() 财务报告和审定财务报表 stop() 钩子. 成功的组件按倒转启动顺序停止 。 遗产 @Bootstrap() 装饰器仍然在类定义时解决,但 被贬后,将在下个大发布会被移除.

安装

不需要外部依赖关系! 该框架与SWC和TypeScript的本土装饰者相配合.

只要确保你有:

  • 类型脚本 5.0+
  • SWC 或 TypeScript 编译器 experimentalDecorators 财务报告和审定财务报表 emitDecoratorMetadata 启用

装饰者完全融入了SWC的本土支持——不需要 reflect-metadata 或任何其他多填充.

快速启动

1. 基本服务

import { Container } from '@di-framework/core/decorators';

@Container()
export class DatabaseService {
  connect(): void {
    console.log('Connected to database');
  }
}

2. 向受抚养人提供服务

import { Container, Component } from '@di-framework/core/decorators';
import { DatabaseService } from './services/DatabaseService';

@Container()
export class UserService {
  @Component(DatabaseService)
  private db!: DatabaseService;

  constructor() {}

  getUser(id: string) {
    return this.db.query(`SELECT * FROM users WHERE id = '${id}'`);
  }
}

注:所有附属物都使用属性注射。 这与SWC和TypeScript的本土装饰器支持无缝地工作.

3. 解决服务

import { useContainer } from '@di-framework/core/container';
import { UserService } from './services/UserService';

const container = useContainer();
const userService = container.resolve<UserService>(UserService);

// All dependencies are automatically injected!
userService.getUser('123');

API 参考

@Container(options?)

标出可注射的类别,并自动在 DI 容器中注册.

选项 :

  • singleton?: boolean (默认 : true- 每次创建新实例或重复使用同一实例
  • container?: DIContainer - 指定自定义容器(默认为全局容器)
    • 注:导入为 import { Container as DIContainer } from '@di-framework/core/container' 避免名称与 @Container 装饰师.

示例

@Container({ singleton: false })
export class RequestScopedService {
  // New instance created for each resolution
}

@Component(target)

标记依赖性注入的构造参数或属性.

参数:

  • target - 为工厂注册服务注入的类别或字符串标识符

示例 - 构造参数:

@Container()
export class OrderService {
  constructor(@Component(DatabaseService) private db: DatabaseService) {}
}

示例 - 属性注入 :

@Container()
export class ReportService {
  @Component(DatabaseService)
  private db: DatabaseService;
}

@Telemetry(options?)

标记一种遥测跟踪方法。 当呼叫时,它发出一个 telemetry 在容器上的活动。 既采用同步方法,又采用同步方法.

选项 :

  • logging?: boolean (默认 : false) - 如果真实,将方法执行细节(状态和持续时间)记录到控制台.

示例

@Container()
export class ApiService {
  @Telemetry({ logging: true })
  async fetchData(id: string) {
    // ...
  }
}

@TelemetryListener()

将一种方法标为遥测事件的听众。 该方法将自动注册到容器的 telemetry 当服务被即时化时.

示例

@Container()
export class MonitoringService {
  @TelemetryListener()
  onTelemetry(event: any) {
    console.log(
      `Method ${event.className}.${event.methodName} took ${event.endTime - event.startTime}ms`,
    );
  }
}

useContainer()

返回全局 DI 容器实例.

import { useContainer } from '@di-framework/core/container';

const container = useContainer();

container.register(serviceClass, options?)

手动注册服务类.

container.register(UserService, { singleton: true });

container.registerFactory(name, factory, options?)

使用工厂功能注册服务.

container.registerFactory(
  'config',
  () => ({
    apiKey: process.env.API_KEY,
    dbUrl: process.env.DATABASE_URL,
  }),
  { singleton: true },
);

container.resolve(serviceClass)

解决并获得一个服务的例子.

const userService = container.resolve<UserService>(UserService);
// or by name
const config = container.resolve('config');

container.has(serviceClass)

检查服务是否注册 .

if (container.has(UserService)) {
  const service = container.resolve(UserService);
}

container.getServiceNames()

获取所有注册服务名 .

const names = container.getServiceNames();
console.log(names); // ['DatabaseService', 'UserService', ...]

container.on(event, listener)

订阅DI容器生命周期事件(观察者模式).

活动 :

  • registered - 某类或工厂注册时被解雇
  • resolved - 服务一经解决即被开除(缝合或新鲜)
  • constructed - 被开除时 construct() 创建新实例
  • cleared - 集装箱清空后发射

示例

const unsubscribe = container.on('resolved', ({ key, fromCache }) => {
  console.log(`Resolved ${typeof key === 'string' ? key : key.name} (fromCache=${fromCache})`);
});

unsubscribe(); // stop listening

container.construct(serviceClass, overrides?)

在不注册的情况下创建新实例,同时尊重依赖性注射。 用于构建者- 平面方案, 您需要提供特定的原始/ 配置值 .

import { Component } from '@di-framework/core/decorators';
import { container } from '@di-framework/core/container';

class LoggerService {
  log(message: string) {
    console.log(message);
  }
}

class Greeter {
  constructor(
    @Component(LoggerService) private logger: LoggerService,
    private greeting: string,
  ) {}
}

const greeter = container.construct(Greeter, { 1: 'hello world' });

container.fork(options?)

将集装箱登记(原型型)划入一个新的集装箱。 过 { carrySingletons: true } 以重用已有的单子实例;默认从新实例开始.

const testContainer = container.fork({ carrySingletons: false });

高级示例

多重依赖

@Container()
export class ApplicationContext {
  constructor(
    @Component(DatabaseService) private db: DatabaseService,
    @Component(LoggerService) private logger: LoggerService,
    @Component(AuthService) private auth: AuthService,
  ) {}

  async initialize() {
    this.logger.log('Initializing application...');
    await this.db.connect();
    this.auth.setup();
  }
}

临时(非英语)服务

@Container({ singleton: false })
export class RequestContext {
  id = Math.random().toString();

  constructor(@Component(LoggerService) private logger: LoggerService) {
    this.logger.log(`Request context created: ${this.id}`);
  }
}

// Each resolve creates a new instance
const ctx1 = container.resolve(RequestContext); // new instance
const ctx2 = container.resolve(RequestContext); // different instance

生命周期方法

服务可选择采用生命周期方法:

@Container()
export class DatabaseService {
  private connected = false;

  setEnv(env: Record<string, any>) {
    // Called to initialize environment-specific config
    console.log('DB URL:', env.DATABASE_URL);
  }

  setCtx(context: any) {
    // Called to set execution context
    console.log('Context:', context);
  }

  connect() {
    this.connected = true;
  }
}

// Calling lifecycle methods
const db = container.resolve(DatabaseService);
db.setEnv(process.env);
db.setCtx({ userId: '123' });
db.connect();

工厂功能

container.registerFactory(
  'apiClient',
  () => {
    return new HttpClient({
      baseUrl: process.env.API_URL,
      timeout: 5000,
    });
  },
  { singleton: true },
);

// Use in services
@Container()
export class UserService {
  constructor(@Component('apiClient') private api: any) {}
}

如何运作

  1. 装饰: 当你装饰一个类 @Container(),装饰者用全球容器进行注册
  2. 登记: 分类存储在容器中, 包含关于依赖性的元数据
  3. 决议: 当你打电话时 container.resolve(ServiceClass)数字 :
    • 容器创建新实例( 或返回已存在的单吨)
    • 它研究了构造参数及其类型
    • 它递相解决了每个依赖
    • 依赖性注入到构造器中
    • 返回已配置实例
  4. 缓存: Singleton 实例被缓存并重新使用

与 SAMPLE.ts 的比较

之前( 手册- SAMPLE. ts)

const createServerContext = (env, ctx) => {
  if (!instanceState.member) {
    const contextInstance = Context.create({
      contactService: ContactService.create({}),
      assetService: AssetService.create({}),
      transactionService: TransactionService.create({}),
      // ... 20+ more services manually created and wired
      chatService: ChatService.create({
        openAIApiKey: env.OPENAI_API_KEY,
        // ... manual configuration
      }),
    });
    instanceState.member = contextInstance;
  }

  instanceState.member.setEnv(env);
  instanceState.member.setCtx(ctx);
  // ... manual dependency wiring
  instanceState.member.knowledgeService.setAttachmentService(
    instanceState.member.attachmentService,
  );
  return instanceState.member;
};

之后( DI 框架)

@Container()
export class ApplicationContext {
  constructor(
    @Component(ContactService) private contactService: ContactService,
    @Component(AssetService) private assetService: AssetService,
    @Component(TransactionService)
    private transactionService: TransactionService,
    // ... all services automatically injected
    @Component(ChatService) private chatService: ChatService,
  ) {}

  setEnv(env: Record<string, any>) {
    // Services are already available via constructor injection
    this.chatService.initialize(env.OPENAI_API_KEY);
  }

  setCtx(ctx: any) {
    // All services have access to context
  }
}

// Usage
const container = useContainer();
const appContext = container.resolve(ApplicationContext);
appContext.setEnv(env);
appContext.setCtx(ctx);

福利:

  • 没有手动服务即时
  • 没有手动依赖线
  • 自动单通管理
  • 类型安全依赖性解决
  • 便于测试(仅通过登记测试实施情况提供模拟服务)
  • 随着服务的增长,规模会更好

处理错误

循环依赖

// This will be detected and throw an error:
@Container()
class ServiceA {
  constructor(@Component(ServiceB) private b: ServiceB) {}
}

@Container()
class ServiceB {
  constructor(@Component(ServiceA) private a: ServiceA) {}
}

// Error: Circular dependency detected while resolving ServiceA

未登记的服务

@Container()
class MyService {
  constructor(@Component(UnregisteredService) private s: UnregisteredService) {}
}

// Error: Service 'UnregisteredService' is not registered in the DI container

最佳做法

  1. 将所有服务标为 @Container() - 明确扶养管理
  2. 使用构造器注入 - 强制性依赖性财产注入优先
  3. 为可选依赖性使用属性注入 - 尽量少
  4. 不需要导入反射元数据 - 这个框架使用轻量级元数据存储
  5. 服务接口与执行分离 - 方便测试
  6. 无国籍人服务使用单数 - 多数服务应为单吨
  7. 使用瞬态(非 singleton)进行状态服务 - 请求/会期服务

测试

// Create a test container
import { Container as DIContainer } from '@di-framework/core/container';

const testContainer = new DIContainer();

// Register mock implementations
class MockDatabaseService {
  query() {
    return { mock: true };
  }
}

testContainer.register(MockDatabaseService);

// Register dependencies
testContainer.register(UserService);

// Test the service with mocked dependencies
const userService = testContainer.resolve(UserService);
expect(userService.getUser('1')).toEqual({ mock: true });

许可证

任何许可 麻省理工学院 或者说 阿帕奇 - 2.0随便你.

私营服务对服务的约束

宣布私人服务对服务的约束,因此服务可以输出可调用合同,经授权的呼叫者可以通过DI通过命名的依赖引用这些合同,而不会暴露公共HTTP端点或网络地址.

1. 申报出口服务

import { Container } from '@di-framework/core/decorators';
import { ExportService } from '@di-framework/core/service-bindings';

@Container()
@ExportService({
  name: 'inventory-service',
  operations: ['reserve', 'release'],
})
export class InventoryService {
  async reserve(items: any[]) {
    return { reservationId: 'res-123' };
  }

  async release(reservationId: string) {
    return { released: true };
  }
}

何时 operations 被省略,类注册在不构建服务的情况下发现原型方法. 明确宣告箭头函数字段,例如 @ExportService({ name: 'inventory-service', operations: ['read'] }) 页:1 read = () => ...当操作启动时,容器解决服务实例。 注册一个已存在的实例也会发现它自己的函数属性.

2. 向打电话者发送装订服务

import { Container } from '@di-framework/core/decorators';
import { ServiceBinding } from '@di-framework/core/service-bindings';

@Container()
export class CheckoutService {
  constructor(
    @ServiceBinding('inventory', {
      caller: 'checkout-service',
      target: 'inventory-service',
    })
    private readonly inventory: InventoryContract,
  ) {}

  async checkout(items: any[]) {
    return await this.inventory.reserve(items);
  }
}

3. 拒绝不受约束的打电话者

未获得明确授权的来电者不得援引目标服务并被拒绝 UnboundCallerError。 。 。 .

4. 地方多服务发展和移动替代

运行多个本地服务, 监视绑定状态

import { LocalServiceDevManager } from '@di-framework/core/service-bindings';

const dev = new LocalServiceDevManager();
dev.registerService('inventory-service', new InventoryService());
dev.bind('checkout-service', 'inventory', 'inventory-service');

console.log(dev.formatStatusTable());

版本与发布记录

@di-framework/core 共发布 40 个版本,首次发布于 2026/08/03;过去 12 个月发布了 40 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
6.1.0latest2026/10/121 个月前
6.0.72026/10/121 个月前
6.0.62026/10/091 个月前
6.0.52026/10/071 个月前
6.0.42026/10/041 个月前
6.0.32026/10/021 个月前

关于 @di-framework/core 的常见问题

@di-framework/core 是什么?

轻量级,零依赖型的TypeScript依赖注射框架使用装饰. 与SWC和TypeScript的本土装饰器支持无缝地工作.

如何安装 @di-framework/core?

在项目目录运行 npm install @di-framework/core,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:typescript(^5)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@di-framework/core 支持 TypeScript 吗?

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

@di-framework/core 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@di-framework/core 可以商用吗?

@di-framework/core 使用 (MIT OR Apache-2.0) 许可。可在 MIT、Apache-2.0 中任选其一遵守。选择 MIT 时,宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@di-framework/core 的下载量有多少?

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

@di-framework/core 还在维护吗?

最新版本 6.1.0 发布于 2026/10/12(1 个月前);至今共发布 40 个版本,其中过去 12 个月发布了 40 个;首次发布于 2026/08/03。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。