Skip to content

Commit cc2dc3a

Browse files
committed
Emit more efficient/concise "empty" ES6 ctor
When there are property assignments in a the class body of an inheriting class, tsc current emit the following compilation: ```ts class Foo extends Bar { public foo = 1; } ``` ```js class Foo extends Bar { constructor(…args) { super(…args); this.foo = 1; } } ``` This introduces an unneeded local variable and might force a reification of the `arguments` object (or otherwise reify the arguments into an array). This is particularly bad when that output is fed into another transpiler like Babel. In Babel, you get something like this today: ```js var Foo = (function (_Bar) { _inherits(Foo, _Bar); function Foo() { _classCallCheck(this, Foo); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _Bar.call.apply(_Bar, [this].concat(args)); this.foo = 1; } return Foo; })(Bar); ``` This causes a lot of needless work/allocations and some very strange code (`.call.apply` o_0). Admittedly, this is not strictly tsc’s problem; it could have done a deeper analysis of the code and optimized out the extra dance. However, tsc could also have emitted this simpler, more concise and semantically equivalent code in the first place: ```js class Foo extends Bar { constructor() { super(…arguments); this.foo = 1; } } ``` Which compiles into the following in Babel: ```js var Foo = (function (_Bar) { _inherits(Foo, _Bar); function Foo() { _classCallCheck(this, Foo); _Bar.apply(this, arguments); this.foo = 1; } return Foo; })(Bar); ``` Which is well-optimized (today) in most engines and much less confusing to read. As far as I can tell, the proposed compilation has exactly the same semantics as before. Fixes #10175
1 parent 269b828 commit cc2dc3a

File tree

3 files changed

+8
-19
lines changed

3 files changed

+8
-19
lines changed

src/compiler/emitter.ts

+2-13
Original file line numberDiff line numberDiff line change
@@ -5311,18 +5311,7 @@ const _super = (function (geti, seti) {
53115311
emitSignatureParameters(ctor);
53125312
}
53135313
else {
5314-
// Based on EcmaScript6 section 14.5.14: Runtime Semantics: ClassDefinitionEvaluation.
5315-
// If constructor is empty, then,
5316-
// If ClassHeritageopt is present, then
5317-
// Let constructor be the result of parsing the String "constructor(... args){ super (...args);}" using the syntactic grammar with the goal symbol MethodDefinition.
5318-
// Else,
5319-
// Let constructor be the result of parsing the String "constructor( ){ }" using the syntactic grammar with the goal symbol MethodDefinition
5320-
if (baseTypeElement) {
5321-
write("(...args)");
5322-
}
5323-
else {
5324-
write("()");
5325-
}
5314+
write("()");
53265315
}
53275316
}
53285317

@@ -5360,7 +5349,7 @@ const _super = (function (geti, seti) {
53605349
write("_super.apply(this, arguments);");
53615350
}
53625351
else {
5363-
write("super(...args);");
5352+
write("super(...arguments);");
53645353
}
53655354
emitEnd(baseTypeElement);
53665355
}

tests/baselines/reference/classExpressionES63.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ let C = class extends class extends class {
1313
}
1414
}
1515
{
16-
constructor(...args) {
17-
super(...args);
16+
constructor() {
17+
super(...arguments);
1818
this.b = 2;
1919
}
2020
}
2121
{
22-
constructor(...args) {
23-
super(...args);
22+
constructor() {
23+
super(...arguments);
2424
this.c = 3;
2525
}
2626
}

tests/baselines/reference/emitClassDeclarationWithPropertyAssignmentInES6.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class D {
3737
}
3838
}
3939
class E extends D {
40-
constructor(...args) {
41-
super(...args);
40+
constructor() {
41+
super(...arguments);
4242
this.z = true;
4343
}
4444
}

0 commit comments

Comments
 (0)