-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incorrect output for #private with nested class in ESNext #41788
Comments
Thanks for highlighting this. I played around and reduced it to a slightly simpler case in the playground. // @target: esnext
class A {
#x : undefined;
static B = class {
constructor() {
new A().#x;
}
}
} ...produces the following incorrect ESnext emit... class A {
#x;
}
A.B = class {
constructor() {
new A().#x;
}
}; ...whereas desired ESnext emit should retain the static field initialization inside the class... class A {
#x;
static B = class {
constructor() {
new A().#x;
}
}
}
Making the static field assignment work without class A {
#x;
static __bornToDie = t=>t.#x;
}
var __get_A_X = A.__bornToDie;
delete A.__bornToDie;
A.B = class {
constructor() {
__get_A_X(new A());
}
}; But this feels like a lot of work for the matter at hand. Maybe the simplest solution would be to make Until this is fixed, users of |
@DanielRosenwasser I suppose |
Why I asked this question, maybe it doesn't make sense, https://github.com/tc39/proposal-class-fields is at Stage 3 too, and TS emits Private fields without polyfills. Example class A {
#x = undefined;
}
// .js
"use strict";
class A {
constructor() {
this.#x = undefined;
}
#x;
} However, TS downgrades static methods/properties. Example class Foo {
static x = 1;
}
// .js
"use strict";
class Foo {
}
Foo.x = 1; |
I like @robpalme's idea of ESNext implying useDefineForClassFields; the emit is simpler and spec-standard class properties are widely enough supported that people overusing target:esnext [1] are unlikely to run into problems. For the explicit combination of (1) target:esnext (2) useDefineForClassFields: false (3) nested static class with private reference, we should add an error that says "you can't do this, change useDefineForClassFields: true, or target an earlier version of ES." [1] for example, somebody who just wants to use every feature in JS without the compiler doing any downlevelling, but who hasn't thought too much about which browser will. |
@sandersn I would like to pick this up if that's ok. Just to clear on the statement of work:
|
…-41788-incorrect-output-for-esprivate-with-nested-class-in-esnext
…-41788-incorrect-output-for-esprivate-with-nested-class-in-esnext
I would strongly discourage using One approach I've seen is to leverage a computed property name, if possible: var B_1;
class A {
#x;
static [(B_1 = class {
constructor() {
new A().#x;
}
}, "B"]() {}
}
A.B = B_1; This, of course, doesn't work if the class has no non-private members, in which case we might have to add an unused member, as you propose, but don't delete it. var <temp variables>;
class A {
#x;
// NOTE: __tsfieldinit__ would be an optimistic unique name
// NOTE: __tsfieldinit__ is a placeholder. It won't actually be evaluated.
static [(<inlined expressions>, "__tsfieldinit__")]() {}
}
<static assignments>
A.__tsfieldinit__ = void 0; // mark undefined, but otherwise leave as is. `delete` is terrible for performance... NOTE: we could possibly abuse var <temp variables>;
class A {
#x;
static [(<inlined expressions>, "name")]() {}
}
Object.defineProperty(A, "name", { value: "A", writable: false }); // fix up A.name
<static assignments>; |
The downside of this is that it could be considered silent breaking change (if you previously used |
We do have other cases where we downlevel things like destructuring to the ES5 form even when targeting ES2015, particularly in the module transforms, which is why |
Found from #41773 (comment)
Currently, this is emitted as
However,
#str
has been orphaned and this code will have errors.CC @robpalme
The text was updated successfully, but these errors were encountered: