new.target本身不能实现依赖注入容器,但可作为自动化绑定的“探测器”:通过识别构造上下文、配合reflect.getmetadata获取参数类型、weakmap检测循环依赖,实现零配置自动解析依赖树。

new.target 本身不能直接实现依赖注入容器,但它能成为自动化绑定的关键“探测器”——帮你判断一个类是否正被 new 调用、是否处于构造阶段,并据此动态推断依赖关系。
识别构造上下文,避免手动注册
依赖注入的核心难点之一是:如何不显式写 container.bind(ServiceA).to(ClassA) 就让容器知道该绑定什么?new.target 在构造函数中指向正在被实例化的类,这提供了“当前谁在被创建”的线索。你可以设计一个基类或装饰器,在构造时捕获 new.target,从而得知当前初始化的是哪个类型。
- 在自定义的
Container.construct()方法中调用目标类的构造函数时,通过Reflect.construct并传入new.target的代理逻辑,就能拦截构造意图 - 配合
Function.prototype.toString()或 TypeScript 的 emitDecoratorMetadata(需开启),可进一步提取构造函数参数类型(如constructor(dep: Logger, config: Config)) - 此时
new.target是MyService,你就知道要为MyService解析并注入其参数所声明的依赖
结合 Reflect Metadata 实现参数类型自动推导
new.target 单独无法读取参数类型,但和 Reflect.getMetadata('design:paramtypes', new.target) 配合,就能拿到构造函数每个参数的构造器数组。这是轻量级自动绑定的真正基础。
- 确保编译选项启用
emitDecoratorMetadata: true和experimentalDecorators: true - 在基类构造函数里检查
if (new.target !== BaseClass),再读取Reflect.getMetadata('design:paramtypes', new.target) - 得到类似
[Logger, ApiClient, Config]的数组后,递归调用容器的get()获取每个依赖实例
防止循环依赖与构造中途访问
利用 new.target 探测到正在构造某类时,若该类已被标记为“正在构建中”,就说明出现循环依赖。这是纯静态分析做不到的运行时保护。
- 维护一个
constructing = new WeakMap<function boolean>()</function>,在调用构造函数前设为true,完成后删除 - 每次通过
new.target查找依赖前,先查constructing.has(new.target),命中则抛出清晰错误 - 这种保护必须发生在构造函数执行前(例如在
container.get(Target)内部),而非等new Target()执行到一半才检测
不侵入业务类的“零配置”绑定策略
最终目标是让开发者只写标准 class,不加装饰器、不手动注册,容器就能工作。这时 new.target 是触发点,不是终点。
- 暴露一个
container.resolve<t>(target: { new(...args: any[]): T })</t>方法,内部用new.target+Reflect自动解析依赖树 - 首次调用
container.resolve(MyService)时,缓存其完整依赖链和实例,后续复用 - 对无参构造函数或工厂函数,仍保留显式
container.bind().toValue()作为兜底,保持灵活性
本质上,new.target 是让你把“谁要被 new”这个动作变成可编程的信号,再叠加元数据和缓存策略,就构成了一个不到 100 行核心逻辑的轻量容器。它不替代 NestJS 或 Inversify,但足够支撑中小型应用的自动装配需求。










