Provider Types
Angular's DI system supports multiple provider types for different scenarios.
useValue — Static Values
import { InjectionToken } from '@angular/core';
export const API_URL = new InjectionToken<string>('API_URL');
@NgModule({
providers: [
{ provide: API_URL, useValue: 'https://api.example.com' },
],
})
export class AppModule {}
useFactory — Dynamic Values
export function loggerFactory(isDev: boolean): LoggerService {
return isDev ? new ConsoleLogger() : new RemoteLogger();
}
@NgModule({
providers: [
{ provide: IS_DEV, useValue: true },
{
provide: LoggerService,
useFactory: loggerFactory,
deps: [IS_DEV],
},
],
})
export class AppModule {}
useClass — Alternative Implementations
@Injectable()
abstract class StorageService {
abstract get(key: string): string | null;
abstract set(key: string, value: string): void;
}
@Injectable()
class LocalStorageService extends StorageService {
get(key: string): string | null {
return localStorage.getItem(key);
}
set(key: string, value: string): void {
localStorage.setItem(key, value);
}
}
@NgModule({
providers: [
{ provide: StorageService, useClass: LocalStorageService },
],
})
export class AppModule {}
useExisting — Aliasing
@NgModule({
providers: [
LoggerService,
{ provide: OldLoggerService, useExisting: LoggerService },
],
})
export class AppModule {}
Provider Comparison
| Type | Use Case |
|---|---|
useValue |
Constants, configuration objects |
useFactory |
Values that depend on other services |
useClass |
Swappable implementations |
useExisting |
Aliasing one token to another |
InjectionToken and multi Providers
InjectionToken creates typed keys for values that are not classes. The multi option collects multiple providers under one token.
InjectionToken
import { InjectionToken } from '@angular/core';
export const HTTP_INTERCEPTORS = new InjectionToken<HttpInterceptor[]>('HTTP_INTERCEPTORS');
export const API_URL = new InjectionToken<string>('API_URL');
export const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG');
Why Not Just Use Strings?
// BAD: String tokens can collide
{ provide: 'apiUrl', useValue: 'https://api.example.com' }
// GOOD: InjectionToken is type-safe and collision-proof
{ provide: API_URL, useValue: 'https://api.example.com' }
multi: true — Multiple Providers
import { HTTP_INTERCEPTORS } from '@angular/common/http';
@NgModule({
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
],
})
export class AppModule {}
With multi: true, each provider is added to an array rather than replacing the previous one. The injector returns an array of all registered interceptors.
Custom Multi-Provider Token
export const VALIDATORS = new InjectionToken<ValidatorFn[]>('VALIDATORS');
export function requiredValidator(control: AbstractControl): ValidationErrors | null {
return control.value ? null : { required: true };
}
export function minLengthValidator(control: AbstractControl): ValidationErrors | null {
return control.value?.length >= 3 ? null : { minLength: true };
}
@NgModule({
providers: [
{ provide: VALIDATORS, useValue: requiredValidator, multi: true },
{ provide: VALIDATORS, useValue: minLengthValidator, multi: true },
],
})
export class AppModule {}
Provider Resolution Order
When multiple providers exist for the same token:
- Component-level providers (highest priority)
- Module-level providers
- Root-level providers (lowest priority)
The last registered provider wins (unless multi: true).
Quiz
1. What is an InjectionToken used for?
2. What does multi: true do in a provider?
3. Which provider type should you use for a value that depends on other services?
Flashcards
Question
What is an InjectionToken?
Click to reveal answer
Answer
A typed key for non-class dependencies. Prevents string collisions and provides type safety.
Question
What does multi: true do?
Click to reveal answer
Answer
Collects multiple providers under one token into an array. Used for HTTP interceptors and validators.
Question
Which provider type for dynamic values?
Click to reveal answer
Answer
useFactory — accepts a function with deps array and returns the computed value.
Revision Notes
Key Takeaways
- 1. InjectionToken creates type-safe keys for non-class values
- 2. useFactory handles values that depend on other services
- 3. multi: true collects providers into an array
- 4. Provider resolution: component > module > root
Interview Tips
- • Explain why InjectionToken is better than string tokens
- • Be ready to describe the multi-provider pattern for interceptors
- • Mention useFactory for environment-specific configuration
Cheat Sheet
Providers and Tokens Cheat Sheet
Provider types:
{ provide: TOKEN, useValue: value }
{ provide: TOKEN, useFactory: fn, deps: [DEP] }
{ provide: TOKEN, useClass: Class }
{ provide: TOKEN, useExisting: OtherToken }
InjectionToken:
export const API_URL = new InjectionToken<string>('API_URL');
Multi-provider:
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }