Skip to content

[typescript-angular] - Remove legacy constructor decorators in favor of native Angular inject() Fn - #24891

Open
kemotx90 wants to merge 4 commits into
OpenAPITools:masterfrom
kemotx90:master
Open

[typescript-angular] - Remove legacy constructor decorators in favor of native Angular inject() Fn#24891
kemotx90 wants to merge 4 commits into
OpenAPITools:masterfrom
kemotx90:master

Conversation

@kemotx90

@kemotx90 kemotx90 commented Sep 7, 2026

Copy link
Copy Markdown

Remove legacy @Inject() / @optional() constructor decorators
Adopt functional inject() API for cleaner dependency injection (https://angular.dev/api/core/inject)

Required update to support "experimentalDecorators": false in new projects

Angular encourages migrating from legacy decorators to the modern inject() function (https://angular.dev/reference/migrations/inject-function).

PR checklist

executed cmd:

./mvnw clean package || exit
./bin/generate-samples.sh bin/configs/typescript-angular* || exit
./bin/utils/export_docs_generators.sh || exit

Summary by cubic

Replaces legacy @Inject() and @Optional() constructor decorators with Angular's functional inject() in the TypeScript Angular generator templates and regenerated samples. This makes generated code compatible with projects that disable experimentalDecorators, matching Angular's modern DI style.

Details

  • Updates api.module.mustache and api.service.mustache to inject HttpClient, BASE_PATH, and Configuration via inject() with optional flags, typing optional results as | null.
  • Regenerates all sample outputs across Angular v18–v22 and other configurations.

Written for commit 27f15f2. Summary will update on new commits.

Review in cubic

kemotx90 and others added 3 commits September 7, 2026 14:48
…ct()

Remove legacy @Inject() / @optional() constructor decorators

Adopt functional inject() API for cleaner dependency injection

Required update to support "experimentalDecorators": false in new projects
…ct()

Remove legacy @Inject() / @optional() constructor decorators

Adopt functional inject() API for cleaner dependency injection

Required update to support "experimentalDecorators": false in new projects
execute ./bin/utils/export_docs_generators.sh

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 52 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/main/resources/typescript-angular/api.service.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/typescript-angular/api.service.mustache:4">
P1: When `ngVersion` is 9–13, this unconditional `inject` import makes the generated client fail to compile even though those Angular versions remain supported. Gate the functional-injection template on the minimum Angular version that provides `inject`, or raise the generator’s supported minimum.</violation>

<violation number="2" location="modules/openapi-generator/src/main/resources/typescript-angular/api.service.mustache:67">
P1: Consumers that instantiate a generated service directly now get `Expected 0 arguments` and cannot construct it outside Angular DI because the field initializer calls `inject`. Preserve a backwards-compatible construction path, or update the generator’s supported public usage and all repository consumers together.</violation>
</file>

<file name="samples/client/others/typescript-angular/builds/composed-schemas/api.module.ts">

<violation number="1" location="samples/client/others/typescript-angular/builds/composed-schemas/api.module.ts:20">
P1: The template now emits `inject()` in class field initializers unconditionally, but the generator still documents support down to Angular 9.0.0. `inject` is only exported from `@angular/core` starting in Angular 14.0, and field-initializer `inject()` requires Angular 14.2+. Any user generating with ngVersion < 14.2 gets code that fails to compile (no `inject` export) or throws NG0203 at runtime. Gate this new pattern behind an `ngVersionAtLeast_14` (or 14.2) conditional in api.module.mustache and keep the legacy `@Optional()/@SkipSelf()` decorator path for older versions, or update the documented minimum supported ngVersion.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

super(basePath, configuration);
protected httpClient: HttpClient = inject(HttpClient);

constructor() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Consumers that instantiate a generated service directly now get Expected 0 arguments and cannot construct it outside Angular DI because the field initializer calls inject. Preserve a backwards-compatible construction path, or update the generator’s supported public usage and all repository consumers together.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/typescript-angular/api.service.mustache, line 67:

<comment>Consumers that instantiate a generated service directly now get `Expected 0 arguments` and cannot construct it outside Angular DI because the field initializer calls `inject`. Preserve a backwards-compatible construction path, or update the generator’s supported public usage and all repository consumers together.</comment>

<file context>
@@ -62,8 +62,13 @@ export class {{classname}} extends BaseService implements {{classname}}Interface
-        super(basePath, configuration);
+    protected httpClient: HttpClient = inject(HttpClient);
+
+    constructor() {
+        super(
+          inject(BASE_PATH, { optional: true }) ?? undefined,
</file context>

/* tslint:disable:no-unused-variable member-ordering */

import { Inject, Injectable, Optional } from '@angular/core';
import { inject, Injectable } from '@angular/core';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When ngVersion is 9–13, this unconditional inject import makes the generated client fail to compile even though those Angular versions remain supported. Gate the functional-injection template on the minimum Angular version that provides inject, or raise the generator’s supported minimum.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/typescript-angular/api.service.mustache, line 4:

<comment>When `ngVersion` is 9–13, this unconditional `inject` import makes the generated client fail to compile even though those Angular versions remain supported. Gate the functional-injection template on the minimum Angular version that provides `inject`, or raise the generator’s supported minimum.</comment>

<file context>
@@ -1,7 +1,7 @@
 /* tslint:disable:no-unused-variable member-ordering */
 
-import { Inject, Injectable, Optional }                      from '@angular/core';
+import { inject, Injectable }                      from '@angular/core';
 import { HttpClient, HttpHeaders, HttpParams,
          HttpResponse, HttpEvent{{#httpContextInOptions}}, HttpContext {{/httpContextInOptions}}
</file context>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC this would break backwards compatibility, so i guess we should avoid that until we officially drop support for ng < 14

constructor( @Optional() @SkipSelf() parentModule: ApiModule,
@Optional() http: HttpClient) {
if (parentModule) {
private parentModule: ApiModule = inject(ApiModule, { optional: true, skipSelf: true });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The template now emits inject() in class field initializers unconditionally, but the generator still documents support down to Angular 9.0.0. inject is only exported from @angular/core starting in Angular 14.0, and field-initializer inject() requires Angular 14.2+. Any user generating with ngVersion < 14.2 gets code that fails to compile (no inject export) or throws NG0203 at runtime. Gate this new pattern behind an ngVersionAtLeast_14 (or 14.2) conditional in api.module.mustache and keep the legacy @Optional()/@SkipSelf() decorator path for older versions, or update the documented minimum supported ngVersion.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/others/typescript-angular/builds/composed-schemas/api.module.ts, line 20:

<comment>The template now emits `inject()` in class field initializers unconditionally, but the generator still documents support down to Angular 9.0.0. `inject` is only exported from `@angular/core` starting in Angular 14.0, and field-initializer `inject()` requires Angular 14.2+. Any user generating with ngVersion < 14.2 gets code that fails to compile (no `inject` export) or throws NG0203 at runtime. Gate this new pattern behind an `ngVersionAtLeast_14` (or 14.2) conditional in api.module.mustache and keep the legacy `@Optional()/@SkipSelf()` decorator path for older versions, or update the documented minimum supported ngVersion.</comment>

<file context>
@@ -17,12 +17,14 @@ export class ApiModule {
-    constructor( @Optional() @SkipSelf() parentModule: ApiModule,
-                 @Optional() http: HttpClient) {
-        if (parentModule) {
+    private parentModule: ApiModule = inject(ApiModule, { optional: true, skipSelf: true });
+    private http: HttpClient = inject(HttpClient, { optional: true });
+
</file context>

@kemotx90 kemotx90 changed the title Remove legacy constructor decorators in favor of native Angular inject() Fn [typescript-angular] - Remove legacy constructor decorators in favor of native Angular inject() Fn Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants