Open
Description
🔎 Search Terms
"nullish coalescing assignment", "private properties", "private fields", "target es2021", "operator precedence"
🕗 Version & Regression Information
- This changed between versions 3.9.7 and 4.0.5
(with the introduction of nullish coalescing assignment)
⏯ Playground Link
(BTW: run it to see the problem)
💻 Code
class Cls {
publicProp: number | undefined;
#privateProp: number | undefined;
noProblem() {
// This works as expected: ternary expression and the nullish coalescing
// assignment are evaluated right-to-left, so the ternary expression is
// grouped and is only evaluated when `this.publicProp` is nullish.
this.publicProp ??= false ? neverThis() : 123;
// This works, because we use parentheses:
this.#privateProp ??= (false ? neverThis() : 20);
}
problem() {
// This fails, because the `??=` is translated to a `??` which has HIGHER
// precedence than the ternary expression.
this.#privateProp ??= false ? neverThis() : 20;
}
}
console.clear();
const r = new Cls;
r.noProblem();
r.noProblem();
console.log('no problem so far');
r.problem();
console.log('no problem at all');
function neverThis(): never {
throw new Error('This should really really never happen!');
}
🙁 Actual behavior
The statement this.#privateProp ??= false ? neverThis() : 20;
is translated into:
__classPrivateFieldSet(this, _Cls_privateProp, __classPrivateFieldGet(this, _Cls_privateProp, "f") ?? false ? neverThis() : 20, "f");
The relevant piece here is:
__classPrivateFieldGet(this, _Cls_privateProp, "f") ?? false ? neverThis() : 20
which is equivalent to:
(__classPrivateFieldGet(this, _Cls_privateProp, "f") ?? false) ? neverThis() : 20
But it should have been:
__classPrivateFieldGet(this, _Cls_privateProp, "f") ?? (false ? neverThis() : 20)
🙂 Expected behavior
Expected correct operator precedence in transpiled code.
Additional information about the issue
This is no issue on targets greater than es2021, because of the native support of private fields.