Somewhere in the build process, after Typescript (tsc) but before AOT.
Don't know.
Code which iterates over a Set is compiled as if Set has a .length property, but it doesn't, the correct property is .size. This silently breaks the logic.
This only happens when using ng build; it doesn't happen with ng serve.
Use ng new to create a minimal project.
Add the following to app.component.ts:
export class AppComponent {
sum = 0;
constructor() {
const numSet = new Set([12, 13, 17]);
for (const num of numSet) {
this.sum += num;
}
console.log(this.sum);
}
}
In tsconfig.json, make just one change:
"target": "es2016",
Run ng build (not in prod mode).
Here's the compiled main-es2016.js:
var AppComponent = /** @class */ (function () {
function AppComponent() {
this.sum = 0;
var numSet = new Set([12, 13, 17]);
for (var _i = 0, numSet_1 = numSet; _i < numSet_1.length; _i++) {
var num = numSet_1[_i];
this.sum += num;
}
console.log(this.sum);
}
return AppComponent;
}());
this.sum should evaluate to 42; instead it evaluates to zero.
This happens because numSet_1.length is undefined. For the Set object, the compiler should have used the .size property, not .length.
Angular Version:
Angular CLI: 8.3.19
Node: 10.15.3
OS: win32 x64
Angular: 8.2.14
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.803.19
@angular-devkit/build-angular 0.803.19
@angular-devkit/build-optimizer 0.803.19
@angular-devkit/build-webpack 0.803.19
@angular-devkit/core 8.3.19
@angular-devkit/schematics 8.3.19
@angular/cli 8.3.19
@ngtools/webpack 8.3.19
@schematics/angular 8.3.19
@schematics/update 0.803.19
rxjs 6.4.0
typescript 3.5.3
webpack 4.39.2
Anything else relevant?
There are plenty of ways to work around this bug, but it's insidious so it really should be fixed.
I can't replicate this in Typescript (with tsc alone), so I assume the problem is in Angular, not in Typescript.
Similarly, if I write:
const numSet = [...new Set([12, 37, 86])];
then with "target": "es2016" it compiles to:
var numSet = new Set([12, 37, 86]).slice();
which also fails, because Set doesn't have a .slice() method.
This only happens in Angular, not in plain Typescript.
Here's the compiled main-es2016.js
this is not es2016 code, but ES5 code. I wonder if somehow ES2016 causes the build pipeline to revert to ES5. What happens when you set the target to ES2015 instead of ES2016?
yeah, we do end up falling back to ES5 mode if you set the target to ES2016.
The issue doesn't reproduce with plain ngc, so I suspect it's a CLI bug. I'll transfer the issue over too the CLI repo.
Looks like you're right, it's just falling back to ES5.
So it's actually a Typescript error in compiling to ES5, which I can replicate using the Typescript playground, though not with tsc alone.
(BTW, the TS behavior is intended. If you need to support iteration in <=ES5, you need to use downlevelIteration.)
I still can't replicate it with tsc alone. My guess is that it's a bug specific to the ES5/ES2015 differential bundle generation.
In file main-es2015.js, I get the correct output (almost the same as Typescript).
In file main-es5.js, it tries to use the .length property of the Set object.
In the compiled for...of loop, the undefined .length is effectively treated as zero. This isn't reported as an error in the browser, so it's particularly hard to discover.
I think this needs to be fixed in Angular.
@clydin - Thanks, that seems to do the trick.
Fixed via #16232
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._