You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
useDefineWithClassFields should use-before-init error when class property initializer refers to parameter property #50971
This bug exists in my project, not only playground, but playground seem to also have bugs, because i can't even seem to reliably reproduce it in the playground – sometimes it does not react on Target change. But right now i have an opened playground tab with this bug.
I will duplicate the MRE code right here as a text.
This is the source code
I'm also sharing the playground link, but i assume it could produce the right code for you if you open it first time.
To reliable reproduce – change module to Node16 and then to CommonJS. You should see this result
Nathan Shively-Sanders (@sandersn) why don't we give an error for referencing a parameter property in a field initializer when useDefineForClassFields is set?
changed the title [-]Target ES2022 + Module CommonJS silently produces code that with TypeError in runtime[/-][+]Target ES2022 + Module CommonJS silently produces code with TypeError in runtime[/+]on Sep 27, 2022
In newer targets, useDefineForClassFields is set to true because it's spec-compliant. To be honest though, even I'm somewhat surprised that we changed the initialization ordering.
even I'm somewhat surprised that we changed the initialization ordering
It’s impossible for facade to be initialized before bug in this code unless the compiler transpiles bug to a constructor-initialized property (as it does pre-ES2022).
Not directly related to the issue but if target is ES2022 (which implies useDefineForClassFields: true) then why isn't this being initialized with defineProperty? Are parameter properties exempt?
Doesn't it reduces readability? I was so happy TypeScript handles initialization ordering in constructor for me.
Now i will be forced to rewrite all such parts in the whole project with less accurate code. At least, as i understand, it requires 2 lines of code instead of 1. One line with field type declaration, and second line with value assignment in constructor.
Reacted by Anton, Witold Kupś, TMTron and Josh Hayden
It looks like our expectation (prior to useDefineForClassFields), was that parameter property initializers are assigned before instance initializers, as evidenced by the emit when useDefineForClassFields is false:
I would contend that the issue is our emit when useDefineForClassFields is true isn't correctly moving the field initializers into the constructor. Really, the emit should be this:
changed the title [-]Target ES2022 + Module CommonJS silently produces code with TypeError in runtime[/-][+]useDefineWithClassFields should use-before-init error when class property initialiser refers to parameter property[/+]on Feb 7, 2023
changed the title [-]useDefineWithClassFields should use-before-init error when class property initialiser refers to parameter property[/-][+]useDefineWithClassFields should use-before-init error when class property initializer refers to parameter property[/+]on Feb 7, 2023
Hi, anything guys? I also faced that, to say more we have ngrx code, which declares multiple effects in a class based on received in the constructor values, but these declared properties are not declared in the constructor. That is overkill.
From other fields, like kotlin or scala - you have a constructor, and later you can use these values from the constructor, to create other properties.
That should be obvious, and IMO it was for many users before ES2022.
Reacted by Elvis Nieves, Jacques P. du Toit, TMTron, Nicolas Breitwieser, N.S. Cutler and ImBrek
Activity
DanielRosenwasser commentedon Sep 27, 2022
I believe that this is due to #36425
Nathan Shively-Sanders (@sandersn) why don't we give an error for referencing a parameter property in a field initializer when
useDefineForClassFieldsis set?[-]Target ES2022 + Module CommonJS silently produces code that with TypeError in runtime[/-][+]Target ES2022 + Module CommonJS silently produces code with TypeError in runtime[/+]dilame commentedon Sep 27, 2022
Is
target: ES2022supposed to produce such code? If i downgrade totarget: ES2021the problem disappearsDanielRosenwasser commentedon Sep 27, 2022
In newer targets,
useDefineForClassFieldsis set to true because it's spec-compliant. To be honest though, even I'm somewhat surprised that we changed the initialization ordering.fatcerberus commentedon Sep 27, 2022
It’s impossible for
facadeto be initialized beforebugin this code unless the compiler transpilesbugto a constructor-initialized property (as it does pre-ES2022).RyanCavanaugh commentedon Sep 27, 2022
The code generation here is as-expected; the bug is the lack of error message to flag the use-before-init.
fatcerberus commentedon Sep 28, 2022
Not directly related to the issue but if
targetis ES2022 (which impliesuseDefineForClassFields: true) then why isn't this being initialized withdefineProperty? Are parameter properties exempt?RyanCavanaugh commentedon Sep 28, 2022
Parameter properties are considered to be sugar for a
this.e = eassignment in the constructor.dilame commentedon Sep 28, 2022
Doesn't it reduces readability? I was so happy TypeScript handles initialization ordering in constructor for me.
Now i will be forced to rewrite all such parts in the whole project with less accurate code. At least, as i understand, it requires 2 lines of code instead of 1. One line with field type declaration, and second line with value assignment in constructor.
rbuckton commentedon Nov 2, 2022
It looks like our expectation (prior to
useDefineForClassFields), was that parameter property initializers are assigned before instance initializers, as evidenced by the emit whenuseDefineForClassFieldsisfalse:I would contend that the issue is our emit when
useDefineForClassFieldsistrueisn't correctly moving the field initializers into the constructor. Really, the emit should be this:AlCalzone commentedon Jan 22, 2023
FWIW, babel also produces code where this is a runtime error.
If this is the desired initialization order, then it should be a compiler error.
[-]Target ES2022 + Module CommonJS silently produces code with TypeError in runtime[/-][+]useDefineWithClassFields should use-before-init error when class property initialiser refers to parameter property[/+][-]useDefineWithClassFields should use-before-init error when class property initialiser refers to parameter property[/-][+]useDefineWithClassFields should use-before-init error when class property initializer refers to parameter property[/+]Back to es2022 but turns off `useDefineForClassFields`
Azbesciak commentedon May 28, 2023
Hi, anything guys? I also faced that, to say more we have ngrx code, which declares multiple effects in a class based on received in the constructor values, but these declared properties are not declared in the constructor. That is overkill.
From other fields, like kotlin or scala - you have a constructor, and later you can use these values from the constructor, to create other properties.
That should be obvious, and IMO it was for many users before ES2022.
Avoids use-before-init w/ useDefineForClassFields
Avoids use-before-init w/ useDefineForClassFields
Adds ambient context to view nodes & fixes ids