angular - Kan vi ta bort alla konstruktorbaserade injektioner?
Nyligen införde Angular en migration för att ersätta konstruktörsbaserad injektion med inject-funktionen.
I de flesta fall är det enkelt och det har tydligt fördelar:
// before
@Injectable({ providedIn: 'root' })
export class SomeSearchService {
constructor(
@Inject(SEARCH_DUE_TIME)
private readonly dueTime: number,
private readonly repositoryService: SomeRepositoryService
) {}
// after: more concise, better typing
@Injectable({ providedIn: 'root' })
export class SomeSearchService {
private readonly dueTime = inject(SEARCH_DUE_TIME);
private readonly repositoryService= inject(SomeRepositoryService);
Kan dock inject-funktionen täcka alla konstruktorbaserade injektionsanvändningar?
Särskilt med useFactory + deps?
För att illustrera har jag denna Stackblitz:
// print.service.ts
@Injectable()
export class PrintService implements IPrintService {
constructor( // QUESTION: can I replace it with `inject` calls?
@Inject(DATA_SERVICE)
private readonly dataService: IDataService,
private readonly logger: LoggingService,
...
) {}
// tokens.ts
export const DATA_SERVICE = new InjectionToken<IDataService>('DATA_SERVICE');
export const FOO_PRINT_SERVICE = new InjectionToken<IPrintService>('FOO_PRINT_SERVICE');
export const BAR_PRINT_SERVICE = new InjectionToken<IPrintService>('BAR_PRINT_SERVICE');
// app.config.ts
export const appConfig: ApplicationConfig = {
providers: [
{
provide: FOO_PRINT_SERVICE,
useFactory: (dataService: IDataService, logger: LoggingService) => new PrintService(dataService, logger),
deps: [FOO_DATA_SERVICE, LoggingService],
},
{
provide: BAR_PRINT_SERVICE ,
useFactory: (dataService: IDataService, logger: LoggingService) => new PrintService(dataService, logger),
deps: [BAR_DATA_SERVICE, LoggingService],
},
...,
],
};
Finns det ett sätt att använda inject & useFactory + deps tillsammans
så att jag kan ersätta constructor-deklarationen i min PrintService med inject-anrop?
Svar #1
Som nämnts av Matthieu Riegler:
om du endast förlitar dig på inject() kan du ta bort experimentalDecorators-alternativet från din TS-konfiguration.
Ja, vi kan använda dem omväxlande.
Vissa scenarier kommer att ha injektionsdekorerare som skipSelf, Optional, Self, Host som kan tillhandahållas som ett andra argument till ett objekt som innehåller dessa egenskaper.
fooPrintService = inject(FOO_PRINT_SERVICE, {
host: false,
optional: false,
self: false,
skipSelf: false,
});
Ur ditt frågeperspektiv behöver du bara skicka injektionstoken till inject-metoden så kan den upptäcka det i DI-trädet.
import { Component, InjectionToken, Injectable, inject } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
export class PrintService {
constructor(public arg: string) {}
}
@Component({
selector: 'app-root',
standalone: true,
template: `
{{fooPrintService.arg}} | {{barPrintService.arg}}
`,
})
export class App {
fooPrintService = inject(FOO_PRINT_SERVICE, {
host: false,
optional: false,
self: false,
skipSelf: false,
});
barPrintService = inject(BAR_PRINT_SERVICE);
name = 'Angular';
}
export const DATA_SERVICE = new InjectionToken<any>('DATA_SERVICE');
export const FOO_PRINT_SERVICE = new InjectionToken<any>('FOO_PRINT_SERVICE');
export const BAR_PRINT_SERVICE = new InjectionToken<any>('BAR_PRINT_SERVICE');
bootstrapApplication(App, {
providers: [
{
provide: FOO_PRINT_SERVICE,
useFactory: () => new PrintService('foo'),
},
{
provide: BAR_PRINT_SERVICE,
useFactory: () => new PrintService('bar'),
},
],
});
