How to Keep Your Angular Providers from Ending Up in the Wrong Injector
In Angular, registering dependency injection providers using plain functions is a common practice. However, when creating such functions, it’s important to consider their intended usage.
For instance, Angular provides several functions like provideHttpClient()
, provideRouter()
, and withDomHydration()
that register providers under the hood. These functions are designed to be used in an environment injector, rather than in a component or a directive injector.
Suppose you’re creating a function like provideSvgIconsConfig()
that registers a provider for SVG icons configuration. If you use this function in a component or a directive injector, you won't see any error. However, this can lead to unexpected behavior or errors down the line.
export function provideSvgIconsConfig(config: Partial<SVG_CONFIG>) {
return {
provide: SVG_ICONS_CONFIG,
useValue: config,
};
}
To prevent this, Angular provides the makeEnvironmentProviders
function that returns an EnvironmentProviders
type. This wrapper type ensures that providers intended for use only in the application/environment injector and not accidentally included in a component or directive injector.
To illustrate this, consider the updated implementation of provideSvgIconsConfig
using makeEnvironmentProviders
:
import { makeEnvironmentProviders } from '@angular/core';
export function provideSvgIconsConfig(config: Partial<SVG_CONFIG>) {
return makeEnvironmentProviders([
{
provide: SVG_ICONS_CONFIG,
useValue: config,
},
]);
}
Now, if you try to use provideSvgIconsConfig
in a component or a directive injector, you'll get a compile error. This makes it easier to catch errors and ensures that providers are used only in the intended context.
Follow me on Medium or Twitter to read more about Angular and JS!