Skip to content

Commit aad05eb

Browse files
clydindylhunn
authored andcommitted
feat(core): support usage of non-experimental decorators with TypeScript 5.0 (#49492)
Previously, attempting to turn off the `experimentalDecorators` TypeScript configuration option within an Angular project would result in build time errors. These errors were due to an exposed Decorator signature from `@angular/core` that TypeScript thought was incompatible with standard decorators. However, Angular's class decorators (`Component`, `Directive`, `Pipe`, `Injectable`, `NgModule`) are actually already compatible with standard decorators. The export types for the decorators only needed to be updated to reflect that compatibility. With the updated exported types, applications will now successfully compile and execute in AOT mode with one important dependency injection caveat explained in the note below. For JIT mode applications that are built with the Angular CLI, `@ngtools/webpack`, or use `tsickle`, there were also no additional changes required. These tools automatically convert property decorators (now called field decorators) at build time to store Angular property metadata directly on the relevant class. Building with these tools is the overwhelmingly common method of building an application. Any applications that do not use one of these tools will not function at runtime in JIT mode if using standard decorators. The behavior and code for when experimental decorators is enabled has been left intact. NOTE: Angular constructor dependency injection that requires parameter decorators is not supported. The standard decorator specification does not support parameter decorators. The `inject` function must be used for all cases that previously required a parameter decorator. This includes such decorators as `Inject`, `Optional`, `Self`, `SkipSelf`, `Host`, and `Attribute`. Constructor dependency injection that relies only on the supplied parameter type will continue to function as expected if using AOT; as well as in JIT mode if using the Angular CLI, `@ngtools/webpack` directly, or `tsickle`. Documentation for the `inject` function can be found at: https://angular.io/api/core/inject The decorator specification proposal can be found at: https://github.com/tc39/proposal-decorators PR Close #49492
1 parent d497be7 commit aad05eb

File tree

2 files changed

+11
-0
lines changed

2 files changed

+11
-0
lines changed

goldens/public-api/core/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,8 @@ export interface TypeDecorator {
14661466
<T extends Type<any>>(type: T): T;
14671467
// (undocumented)
14681468
(target: Object, propertyKey?: string | symbol, parameterIndex?: number): void;
1469+
// (undocumented)
1470+
(target: unknown, context: unknown): void;
14691471
}
14701472

14711473
// @public

packages/core/src/util/decorators.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export interface TypeDecorator {
3434
// so we cannot declare this interface as a subtype.
3535
// see https://github.com/angular/angular/issues/3379#issuecomment-126169417
3636
(target: Object, propertyKey?: string|symbol, parameterIndex?: number): void;
37+
// Standard (non-experimental) Decorator signature that avoids direct usage of
38+
// any TS 5.0+ specific types.
39+
(target: unknown, context: unknown): void;
3740
}
3841

3942
export const ANNOTATIONS = '__annotations__';
@@ -152,6 +155,12 @@ export function makePropDecorator(
152155
const decoratorInstance = new (<any>PropDecoratorFactory)(...args);
153156

154157
function PropDecorator(target: any, name: string) {
158+
// target is undefined with standard decorators. This case is not supported and will throw
159+
// if this decorator is used in JIT mode with standard decorators.
160+
if (target === undefined) {
161+
throw new Error('Standard Angular field decorators are not supported in JIT mode.');
162+
}
163+
155164
const constructor = target.constructor;
156165
// Use of Object.defineProperty is important because it creates a non-enumerable property
157166
// which prevents the property from being copied during subclassing.

0 commit comments

Comments
 (0)