Skip to content

property decorators break at runtime with ES2015 and circular deps #30141

@filipesilva

Description

@filipesilva

🐞 bug report

Affected Package

The issue is caused by package @angular/core

Is this a regression?

No

Description

Using the `@Input()` property decorator (or any other property decorators I imagine) targetting ES2015 with a circular dependency on a type will cause a `Uncaught ReferenceError` at runtime.

🔬 Minimal Reproduction

git clone https://github.com/filipesilva/istiti-circular-deps-es2015
cd istiti-circular-deps-es2015
ng serve
# src/app/autocomplete.directive.ts contains the problematic decorator and circular dep

🔥 Exception or Error


main.js:9545 Uncaught ReferenceError: Cannot access 'AutocompleteAbstract' before initialization
    at Module.AutocompleteAbstract (main.js:9545)
    at Module../src/app/autocomplete.directive.ts (main.js:9580)
    at __webpack_require__ (runtime.js:79)
    at Module../src/app/autocomplete.abstract.ts (main.js:9546)
    at __webpack_require__ (runtime.js:79)
    at Module../src/app/parent.component.ts (main.js:9605)
    at __webpack_require__ (runtime.js:79)
    at Module../src/app/app.module.ts (main.js:9507)
    at __webpack_require__ (runtime.js:79)
    at Module../src/main.ts (main.js:9666)

🌍 Your Environment

Angular Version:


Angular CLI: 8.0.0-beta.16
Node: 10.10.0
OS: win32 x64
Angular: 8.0.0-beta.13
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.800.0-beta.16
@angular-devkit/build-angular     0.800.0-beta.16
@angular-devkit/build-optimizer   0.800.0-beta.16
@angular-devkit/build-webpack     0.800.0-beta.16
@angular-devkit/core              8.0.0-beta.16
@angular-devkit/schematics        8.0.0-beta.16
@angular/cli                      8.0.0-beta.16
@ngtools/webpack                  8.0.0-beta.16
@schematics/angular               8.0.0-beta.16
@schematics/update                0.800.0-beta.16
rxjs                              6.4.0
typescript                        3.4.4
webpack                           4.30.0

Anything else relevant?

cc @istiti

This is similar to #30106. In this case it is not a constructor parameter type, but rather a class property type.

A class property by itself doesn't need metadata with a type reference:

// transpiled src/app/autocomplete.directive.ts without Input() decorator
import * as tslib_1 from "tslib";
import { Directive } from '@angular/core';
let AutocompleteDirective = class AutocompleteDirective {
    constructor() { }
};
// this is used in autocomplete.abstract.ts
AutocompleteDirective.EMPTYLIST_ELEMENT = "_EMPTYLIST_";
AutocompleteDirective = tslib_1.__decorate([
    Directive({
        selector: '[appAutocomplete]'
    }),
    tslib_1.__metadata("design:paramtypes", [])
], AutocompleteDirective);
export { AutocompleteDirective };

But when the property is decorated, the metadata will contain a reference to the type:

// transpiled src/app/autocomplete.directive.ts with Input() decorator
import * as tslib_1 from "tslib";
import { Directive, Input } from '@angular/core';
import { AutocompleteAbstract } from './autocomplete.abstract';
let AutocompleteDirective = class AutocompleteDirective {
    constructor() { }
};
// this is used in autocomplete.abstract.ts
AutocompleteDirective.EMPTYLIST_ELEMENT = "_EMPTYLIST_";
tslib_1.__decorate([
    Input('appAutocomplete'),
    tslib_1.__metadata("design:type", AutocompleteAbstract)
], AutocompleteDirective.prototype, "autocomplete", void 0);
AutocompleteDirective = tslib_1.__decorate([
    Directive({
        selector: '[appAutocomplete]'
    }),
    tslib_1.__metadata("design:paramtypes", [])
], AutocompleteDirective);
export { AutocompleteDirective };

In ES5 there are no class declarations, so TS instead uses a var. One important different between var and class/let/const is that the latter are all subject to the Temporal Dead Zone.

Without the Input() decorator this isn't a problem because there is no circular dependency on the type.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions