Repository navigation
useDefineWithClassFields should use-before-init error when class property initializer refers to parameter property #50971
Description
Activity
DanielRosenwasser commented
on Sep 27, 2022 MemberMore actionsI 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?Reacted by Matt Bierner- 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 Is
target: ES2022supposed to produce such code? If i downgrade totarget: ES2021the problem disappearsDanielRosenwasser commented
on Sep 27, 2022 MemberMore actionsIn 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.even I'm somewhat surprised that we changed the initialization ordering
It’s impossible for
facadeto be initialized beforebugin this code unless the compiler transpilesbugto a constructor-initialized property (as it does pre-ES2022).- addedBugA bug in TypeScriptA bug in TypeScriptHelp WantedYou can do thisYou can do this
on Sep 27, 2022 RyanCavanaugh commented
on Sep 27, 2022 MemberMore actionsThe code generation here is as-expected; the bug is the lack of error message to flag the use-before-init.
Reacted by Rob Palmer, Matt Bierner, Matthieu Riegler, Mark Roberts and ZzzenReacted by Alex Okrushkothis.facade = facade;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 commented
on Sep 28, 2022 MemberMore actionsParameter properties are considered to be sugar for a
this.e = eassignment in the constructor.The code generation here is as-expected
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 HaydenIt looks like our expectation (prior to
useDefineForClassFields), was that parameter property initializers are assigned before instance initializers, as evidenced by the emit whenuseDefineForClassFieldsisfalse:constructor(facade) { this.facade = facade; this.bug = this.facade.create(); console.log(this.bug); }
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:facade; bug; constructor(facade) { this.facade = facade; this.bug = this.facade.create(); console.log(this.bug); }
Reacted by Anton, Andrew Scott, Johnathan Ritzi, Witold Kupś, Dmitry, Jacques P. du Toit, TMTron and Nicolas BreitwieserFWIW, babel also produces code where this is a runtime error.
If this is the desired initialization order, then it should be a compiler error.Reacted by Elvis Nieves and Michał Mrozek- 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 - added a commit that references this issue
on Feb 10, 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- added a commit that references this issue
on Jun 12, 2023 - added 2 commits that reference this issue
on Jun 12, 2023 - locked as resolved and limited conversation to collaborators
on Oct 22, 2025
Bug Report
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
Targetchange. 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
This is the compiled code with
target: ES2022andmodule: CommonJSIf run this JS – we will get TypeError
⏯ Playground Link
Playground link with relevant 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
moduletoNode16and then toCommonJS. You should see this result