能否移除Angular中所有基于构造函数的注入?含useFactory+deps场景
Angular中inject函数能否覆盖useFactory+deps的注入场景?
可以用inject函数覆盖useFactory+deps的注入场景,但需要调整实现逻辑——不能直接在PrintService的构造函数里把参数替换成inject调用(因为手动new PrintService()时不在Angular注入上下文,会触发错误),而是要结合注入上下文的特性优化provider和服务的写法。
核心问题解析
原来的useFactory+deps是手动传递依赖实例给PrintService,而inject函数只能在Angular注入上下文(组件/服务构造函数、类字段初始化、Angular提供的工厂函数内部等)中调用。如果直接把PrintService的构造函数参数换成inject,手动new时会报错,因为此时没有注入上下文支持。
解决方案1:将PrintService改为纯inject类+覆盖注入令牌
把PrintService改造成完全依赖inject的类(无构造函数参数),然后在provider中通过嵌套的providers覆盖DATA_SERVICE令牌,让不同的打印服务使用对应的数据服务:
// 改造后的print.service.ts @Injectable() export class PrintService implements IPrintService { // 直接用inject获取依赖,无需构造函数参数 private readonly dataService = inject(DATA_SERVICE); private readonly logger = inject(LoggingService); constructor() {} }
// 改造后的app.config.ts export const appConfig: ApplicationConfig = { providers: [ // FOO打印服务:覆盖DATA_SERVICE为FOO_DATA_SERVICE { provide: FOO_PRINT_SERVICE, useClass: PrintService, // 嵌套providers,仅在当前provider范围内覆盖令牌 providers: [{ provide: DATA_SERVICE, useExisting: FOO_DATA_SERVICE }] }, // BAR打印服务:覆盖DATA_SERVICE为BAR_DATA_SERVICE { provide: BAR_PRINT_SERVICE, useClass: PrintService, providers: [{ provide: DATA_SERVICE, useExisting: BAR_DATA_SERVICE }] }, // 注册基础依赖 { provide: FOO_DATA_SERVICE, useClass: FooDataService }, { provide: BAR_DATA_SERVICE, useClass: BarDataService }, LoggingService ], };
这种写法完全去掉了useFactory和deps,利用Angular的注入层次特性实现依赖替换,同时保留了inject的简洁性和类型安全性。
解决方案2:保留useFactory,在工厂函数内部用inject获取依赖
如果需要保留工厂函数的灵活性,可以在工厂函数内部用inject获取依赖,再传递给PrintService(此时PrintService可以保留构造函数,或者也改用inject):
// print.service.ts(可选保留构造函数) @Injectable() export class PrintService implements IPrintService { constructor( private readonly dataService: IDataService, private readonly logger: LoggingService ) {} // 或者改用inject,去掉构造函数参数: // private readonly dataService = inject(DATA_SERVICE); // private readonly logger = inject(LoggingService); // constructor() {} }
// 改造后的app.config.ts export const appConfig: ApplicationConfig = { providers: [ { provide: FOO_PRINT_SERVICE, useFactory: () => { // 在工厂函数内部(注入上下文)用inject获取对应依赖 const dataService = inject(FOO_DATA_SERVICE); const logger = inject(LoggingService); return new PrintService(dataService, logger); }, // 无需deps数组,inject会自动解析依赖 }, { provide: BAR_PRINT_SERVICE, useFactory: () => { const dataService = inject(BAR_DATA_SERVICE); const logger = inject(LoggingService); return new PrintService(dataService, logger); }, }, // 注册基础依赖 { provide: FOO_DATA_SERVICE, useClass: FooDataService }, { provide: BAR_DATA_SERVICE, useClass: BarDataService }, LoggingService ], };
这种写法去掉了deps数组,避免了数组顺序错误的风险,同时inject提供了更好的类型提示。
总结
inject函数可以完全覆盖useFactory+deps的场景,且能带来更简洁、类型更安全的代码;- 核心是确保
inject调用处于Angular的注入上下文之中,避免在手动new实例时调用inject; - 优先推荐方案1的写法,利用Angular注入层次特性简化代码结构。
内容的提问来源于stack exchange,提问作者fservantdev
相关产品推荐
相关产品推荐

