Closed
Description
- useDefineForClassFields defaults to true when target is es2022, breaks decorators. #48814
useDefineForClassFields
under ES2022- Background: If you have a decorator on a class field that tries to replace it with an accessor, that only works under UDFCF (i.e
[[Set]]
semantics), it breaks under ES[[Define]]
semantics - Most decorators assume
[[Set]]
semantics - Most people, rightly, don't know/care the difference
- Using latest always seems nice! But this breaks your decorators
- We changed UDFCF to
true
inES2022
in 4.2 - Our explanation of why you got broke is very logical and correct, but it still sucks and no one can figure out why, plus there are no guardrails
- Proposal: Disallow
experimentalDecorators
(ED) + UDFCF - Counter-argument: not all uses of ED & UDFCF are broken. Only some decorators are broken by
[[Define]]
semantics target: es2022
must imply UDFCF- Q: Can you write a replacement decorator that does this?
- A: No
- Observation: The use of
defineProperty
inobserve
here is not an intended use of experimental decorators- Intended by whom?
- The proposal authors
- Who cares? It worked without error
- Anyway, most field decorators are for metadata, and are not broken, and would work under ED & UDFCF
- We can add the
accessor
keyword, which is in the Stage 3 proposal, and let people fix themselves - Proposal: Let it be - people can use the
declare
keyword. User education problem.- Problem: Library authors can't tell that you're misconfigured
- It's called
experimentalDecorators
🧪, and we didn't move thetarget
ourselves - this is "the user's fault" to the best degree that it can be mobx
uses this pattern and the "misuse" described above seems extremely common- Q: Library authors can tell users to add
declare
and fix this? A: Yes, but no one reads the docs - Q: Library authors can write a lint rule for users? A: Yes, but no one reads the docs
- Conclusion: Do nothing, suggest a lint rule
- Background: If you have a decorator on a class field that tries to replace it with an accessor, that only works under UDFCF (i.e
- Improve intersection reduction and CFA for truthy, equality, and typeof checks #49119 Narrowing of
unknown
and unconstrained type parametersNonNullable
today is a conditional type, which has many drawbacks- Ideally it could just be
type NonNullable<T> = T & { }
- (Read the PR notes)
- Interesting cases in generics involve exclusions, either via
else
or!==
if (x !== undefined) { const x1 = x } else { const x2 = x }
x2
getsT
when it could beT & undefined
, but this means the CFA join points produce types likeT & {} | T & null | T & undefined
and require a new unification rule to convert that back toT
- Other potential further work involves e.g.
if (x === 'a' || x == 'b') {
could narrow toT & 'a' | T & 'b'
{}
now narrows toobject
viatypeof === 'object'
- Generic type no longer narrowed as expected without
extends object
#48468 is successfully mitigated - What's potentially stopping us from changing
NonNullable = T & { }
?- Esoteric breaks!
function c<T extends string | number, U extends number | boolean>(x: T & U) {
- The effective constraint type of
x
should benumber
but we don't have logic to do that - Conditional types have logic to resolve this situation but intersections/unions do not
- It looks like we can proceed and handle the breaks