Skip to content
ToolShedby Wasim Shaikh

Angular inject() Converter

Paste an Angular component, directive or service and convert constructor injection to the inject() function: @Inject, @Optional, @Self, @SkipSelf, @Host, @Attribute and super() calls, with the official migration rules and optional @Service().

Examples:
inject() version
Loading the converter…
Options

The last three match the options of the official ng generate @angular/core:inject migration.

From Constructor Injection to inject()

Angular can inject dependencies through constructor parameters or with the inject() function, and its style guide now recommends inject(). Angular 22 goes further: its new @Service() decorator only works with inject(). Paste a component, directive, pipe or service above and the converter turns each constructor parameter into an inject() field, moves the parameter decorators into inject() options, keeps any constructor code working, and tidies the imports from @angular/core.

Constructor Injection to inject() Cheat Sheet

Constructor injectioninject()
constructor(private http: HttpClient) {}private http = inject(HttpClient);
constructor(public store: Store) {}store = inject(Store);
@Inject(DOCUMENT) private doc: Documentprivate doc = inject<Document>(DOCUMENT);
@Inject(API_URL) private url: stringprivate url = inject(API_URL);
@Optional() private log?: Loggerprivate log = inject(Logger, { optional: true });
@Self() / @SkipSelf() / @Host(){ self: true } / { skipSelf: true } / { host: true }
@Attribute('type') type: stringtype = inject(new HostAttributeToken('type'), { optional: true });
@Inject(forwardRef(() => Parent))inject(Parent)
private x: X = fallbackprivate x = inject(X) ?? fallback;
@Injectable({ providedIn: 'root' })@Service() (Angular 22+)
@Injectable()@Service({ autoProvided: false }) (Angular 22+)

Migrating a Whole Project

The Angular CLI ships the same migration as a schematic. Run it from the project root, optionally limited to one folder with --path, and review the diff before you commit.

ng generate @angular/core:inject

It takes the same options as this page: --backwards-compatible-constructors, --non-nullable-optional and --migrate-abstract-classes. On Angular 22, a second migration then switches every @Injectable that no longer uses constructor injection to @Service(), which is what “Use @Service()” does here.

ng generate @angular/core:service

Frequently Asked Questions

How do I migrate a whole Angular project to inject()?
Run ng generate @angular/core:inject. It converts every component, directive, pipe, NgModule and @Injectable class in the project. This converter applies the same rules to one file at a time, so you can review the result first, convert a snippet, or learn the inject() equivalents. Its output matched the official migration on every sample we compared, apart from whitespace: it only rewrites the code it changes and keeps your formatting.
What happens to code in the constructor body?
The constructor loses its parameters but keeps its code. A parameter the body still reads becomes a local variable: const renderer = this.renderer; for a parameter that declared a property, or const el = inject(ElementRef); for one that didn’t. An empty constructor is removed.
How is super() handled?
this can’t be used before super(), so a parameter passed to super() is injected into a local variable first: const el = inject(ElementRef); super(el);. If the parent class was migrated too, it no longer takes parameters, so remove the arguments from super() or turn on "Backwards-compatible constructors", which keeps a constructor(...args: unknown[]) signature in the parent.
Why is inject(X, { optional: true }) typed X | null?
Because that is what Angular returns when nothing is provided. @Optional() couldn’t change a parameter’s type, so code often declared it as X and ignored the null. If TypeScript now reports possible nulls, handle them, or turn on "Non-nullable optional" to add ! after those calls. Parameters already typed as nullable or marked with ? never get the !.
What is @Service() in Angular 22?
Angular 22 added @Service() as a shorter @Injectable({ providedIn: 'root' }). It only works with inject(): a @Service class can’t use constructor injection, and the compiler reports an error if it does. It also has no useClass, useValue, useExisting or useFactory options (use its factory option instead) and no providedIn: 'platform' or 'any'. @Injectable still works, so switching is optional. Turn on "Use @Service()" to convert services once their constructors are migrated, using the same rules as ng generate @angular/core:service. A service that still has (or inherits) constructor parameters, or uses other @Injectable options, keeps @Injectable.
Why was a class skipped?
The converter, like the official migration, only changes classes Angular injects: those with @Component, @Directive, @Pipe, @NgModule or @Injectable. It also skips a class when a parameter can’t be injected, such as a string or number without an @Inject() token, and abstract classes unless you turn on "Migrate abstract classes". Each skipped class is listed with the reason.
Is inject() better than constructor injection?
Angular’s style guide recommends inject(). It reads better when a class has many dependencies, gives better type inference, and lets a field initializer use an injected service directly. It also works in functions that run in an injection context, such as functional guards and resolvers. Both styles inject exactly the same instances.
Is my code uploaded anywhere?
No. The conversion runs entirely in your browser.

Sources & Official Resources

The conversion rules follow Angular's inject and service migration schematics. Last reviewed against Angular 22.2.

Upgrading Angular too? The Angular Upgrade Planner lists every step between two versions, and the Control Flow Converter rewrites *ngIf and *ngFor. More in Angular tools.