-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Disallow uninitialised property overrides #33423
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
Conversation
This causes quite a few test breaks. We'll probably want to revert many of them by switching to the upcoming `declare x: number` syntax.
@typescript-bot test this |
The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master. |
Is there any way how I can test my code against this? From reading your recent PRs it seems that one of my libraries will be affected by the change. |
Will update after checking out other branch for a minute
@typescript-bot pack this The extended tests look pretty grim, but at least this error will be pretty easy to fix. |
Hey @sandersn, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running |
Need to test properties initialised in constructor
@typescript-bot test this |
The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master. |
The codefix is in -- @rbuckton I think this is ready for review now. |
And simplify redundant parts of check.
@@ -29583,6 +29603,9 @@ namespace ts { | |||
} | |||
const constructor = findConstructorDeclaration(node); | |||
for (const member of node.members) { | |||
if (getModifierFlags(member) & ModifierFlags.Ambient) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do not require !
on declare x: number
(since it is in fact not even allowed)
It seems useful to ship |
@ljharb Our current plan is to ship the new syntax, the new errors, and the flag to switch to Define semantics at the same time. The flag will initially default to Set semantics, which also silences the errors. People can switch the flag on, fix errors, then switch it off again. Notably, the fixes for both errors are the same with both Set and Define semantics. We'll discuss this at our design meeting on Friday so we should have a final decision then. |
Mainly thinking that the declare syntax is at least explicit, and that you may want to hold off merging the rest until after the next TC39 meeting, in case the topic comes up. (not trying to imply anything will change about the proposal) |
The errors in #33401 that disable accessor/property override mismatch are independently useful, although admittedly we haven't got many complaints from people confused by the current Set behaviour. |
Note: this-property assignments are still incorrectly erroring in JS. |
@ljharb I don't see anything on the October 2019 TC39 agenda about this topic, and the deadline for adding agenda items has passed. Class fields have been stable with Define semantics for the whole time they have been at Stage 3, since 2017, and these semantics have shipped unflagged in Firefox, Chrome, and Node.js, as well as other environments. |
The deadline is for stage advancement; there’s no deadline for discussion topics, which is what i was alluding to. |
@sandersn Surprisingly little errors (only 3) in my codebase. I guess I squashed most of them when I switched testing to Babel+Jest. Back then I switched from redefining the class properties to interface merging, i.e. class BaseClass {
property: number
}
interface SubClass {
property: 1 | 2 | 3
}
class SubClass extends BaseClass {
// ...implementation
} which is the ugly brother of the |
This is now included in #33509. Thanks all for testing. @AlCalzone we decided that interface merging is too esoteric a fix to recommend for the number of errors this causes. Also it's harder to write a codefix for. @ljharb After our design meeting: #33509 has everything in one PR, and will keep the errors behind a flag while adding the new syntax for everyone to use. |
@sandersn is |
Yes. Well, |
👍🏻 |
This PR is part of the migration from [[Set]] semantics to [[Define]] semantics. #27644 tracks the complete migration. This is the third step.
Briefly, uninitialised property declarations that must now use new syntax when the property overrides a property in a base class. The new syntax is only allowed in this case and is an error elsewhere. That's because when Typescript supports [[Define]] semantics, it will start emitting uninitialised property declarations, where previously it did not. This will be a major breaking change:
Previously this emitted
When Typescript supports [[Define]] semantics, it will instead emit
which will give both
B
andC
and propertyp
with the valueundefined
. (This is an error today withstrictNullChecks: true
.)The new syntax will cause Typescript to emit the original JS output:
This PR adds an error prompting the author to add the new syntax in order to avoid the breaking change. As you can see from the baselines, this error is pretty common. From my first run of our extended test suites, it looks pretty common in real code as well.
Note that the compiler can only check constructors for initialisation when
strictNullChecks: true
. I chose to be conservative and always issue the error forstrictNullChecks: false
.Other ways to fix the error
"strictNullChecks": true
.Notes
!
is always erased, so, in the last example,p!: 256 | 1000
would still result inp === undefined
for [[Define]] semantics.declare
to any uninitialised property, even if it's not an override. I previously had a check that prevented this, but I think an easy upgrade is valuable (you can almost write a regex for it).To test this PR
Future work
The upcoming flag to change class field emit to [[Define]] semantics should disable this error.