Skip to content
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

Incorrect operator precedence when using private fields with nullish coalescing assignment for targets <= es2021 #61109

Open
pavadeli opened this issue Feb 4, 2025 · 0 comments
Assignees
Labels
Bug A bug in TypeScript

Comments

@pavadeli
Copy link

pavadeli commented Feb 4, 2025

🔎 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

https://www.typescriptlang.org/play/?noUnusedLocals=true&noUnusedParameters=true&target=8&jsx=0&noFallthroughCasesInSwitch=true&useUnknownInCatchVariables=true&ts=5.8.0-dev.20250204&ssl=6&ssc=1&pln=9&pc=1#code/MYGwhgzhAEDCIwN4ChpugBwK4CMQEtgAFAJwHsMAuaAOywFscBTE6AH2ixoBMmAzfDSbcA3KnQBiDCXwA3MABcmpCtTqMW7Tj36DhY8WhpkVeJvQAUASmgp096AHpH0ACoALfDADuZEgGsYSGgmAA8MJmAlbmolEhowEgBPEPCSJih8MhpoMB5oBXcmWiwQAgh3aGAyMBAM4EEAc0MHZ1zMxpp6JhoFXPSQ+RAsRWFoGUb3BQBaBTJpur4FABpoCDICooKWBOTU6QyILJyvFvs2xvIsCO5c-K9obJAUpiGR6OhvIpyAA0KvAB02DwhBUGB+0AedDKXncALO6H+ECBuAIxHIGGgAH4sQBeaB8WoQYpY2ivFgeLzWaDUACMACYAMxiBzoNqUnx+QKrZjAMBYYmfYoC4oYRI9QoZDKUBFoJEAqQyeRKMHYvHQCyEhAksmyCmeCDU6j0gAMVhZ6AAvsgWtIyGZLDY7KynC4OQSwPgEDzIvzBZLoD8cbiIQ8FCQ8hBwB85rlAziIV9CJV3MEABIASQA4mmAKIAJVlrsw6WAwh6Zc2eU2xTiuxeaUOx3hLs2gMVclGquDHu12N1+qpNmNJotaGt1uQ1Ro6zqANATES1gM04gfVY+KE3jgCDEJABxlMdUde4PJnIDuXNtXZDnIDIjQsAHJjCX7ce1htCSQn+abfu7UvP8p2yWcmABe9HxfDZAI-RRcjKX8DD4LgomOAcSA5aw1HJVhnTldxyG3LdoFzEhyBIZ93QqMhSludJamecZFzKFIhD1VhUwwCIaAAQiQ5BLSAA

(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.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Feb 4, 2025
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 5.8.0 milestone Feb 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants