Skip to content

Account for discrepancy between soft privacy of private vs hard privacy of # #44670

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

Open
rpivo opened this issue Jun 19, 2021 · 10 comments
Open
Labels
Docs The issue relates to how you learn TypeScript

Comments

@rpivo
Copy link

rpivo commented Jun 19, 2021

With the upcoming TC39 class fields proposal landing in 2022, there is a soft private vs hard private discrepancy between vanilla JS' # and TypeScript's private. This discrepancy might not be obvious to all users and could cause issues.

Maybe the TS docs should highlight this discrepancy, or maybe we should have some kind of warning. Alternatively (and this would have to be raised elsewhere), maybe there should be a TypeScript ESLint warning for this.

TypeScript's private is soft private and has escape hatches like the ability to use bracket notation to access a private field.

The new # private field prefix is hard private and doesn't allow for this. In the example below, TS compiles private and # differently, and the console log at the bottom shows that accessing these values produces different results.

class Dog {
  #barkAmount = 0;
  personality = "happy";

  constructor() {}
}

class Cat {
    private meowAmount = 0;
    personality = "angry";

    constructor() {}
}

const fido = new Dog();
const garfield = new Cat();

console.log(
    fido.#barkAmount, // no good
    fido['#barkAmount'], // no good
    garfield.meowAmount, // no good
    garfield['meowAmount'] // fine
);

Compiles to:

"use strict";
class Dog {
    constructor() {
        this.#barkAmount = 0;
        this.personality = "happy";
    }
    #barkAmount;
}
class Cat {
    constructor() {
        this.meowAmount = 0;
        this.personality = "angry";
    }
}
const fido = new Dog();
const garfield = new Cat();
console.log(fido.#barkAmount, fido['#barkAmount'], garfield.meowAmount, garfield['meowAmount']);
@IllusionMH
Copy link
Contributor

Is it feature request or what action you are expecting? If it's feature request - please update issue to match Feature request template.

There is warning in docs https://www.typescriptlang.org/docs/handbook/2/classes.html#caveats for private and link to ES Private Fields in same explanation.

@rpivo
Copy link
Author

rpivo commented Jun 20, 2021

Thanks @IllusionMH -- I didn't notice this. I searched the docs for # in reference to the new private fields proposal, but didn't find anything that way.

If you think that the docs are sufficient in preventing any future confusion with the use of # vs private, then feel free to close this.

@nmain
Copy link

nmain commented Jun 21, 2021

@rpivo It might help if you gave an example of an exact situation in code where you expected an error or warning, but the current compiler didn't give one. All three of the "no good" lines in your example already give errors in the current compiler.

@rpivo
Copy link
Author

rpivo commented Jun 21, 2021

@nmain I think it's more about why the first three error and the last one doesn't. People might approach private and # thinking that they have the same behavior given that they both are used to represent private fields.

When I first started looking into this, I figured private and # would compile to the same thing.

I think the docs could elaborate on this a bit more than they do. From the docs:

If you need to protect values in your class from malicious actors, you should use mechanisms that offer hard runtime privacy, such as closures, weak maps, or private fields.

@fatcerberus
Copy link

When I first started looking into this, I figured private and # would compile to the same thing.

They can't, because private was part of TS long before # private fields were a thing, exists only at the type level, and now can't be changed because of backwards compatibility. # by contrast is specified--including in runtime behavior--by ECMAScript.

@rpivo
Copy link
Author

rpivo commented Jun 21, 2021

@fatcerberus to be clear, I'm not suggesting typescript updates their private logic. I think having both private and # available presents some interesting tradeoffs. I think it makes a lot of sense for them to coexist. I'm more saying that these differences and tradeoffs might not be so obvious to others.

@RyanCavanaugh
Copy link
Member

See also #31670

I think the docs could elaborate on this a bit more than they do. From the docs:

The language in there is precise and actionable. What more do you think should be said?

@rpivo
Copy link
Author

rpivo commented Jun 21, 2021

@RyanCavanaugh I think a small example showing different compilation results could be helpful, and maybe even tradeoffs that could be considered (eg, can hard privacy have effects on performance? maybe just statically checked privacy is all that a project needs? what are the escape hatches that TS provides?). I think knowing the difference between hard privacy and soft privacy might not be so obvious to a lot of people.

I guess I would expect more people to not know these differences as # becomes more popular. Even though the docs do mention this, I feel like it could be highlighted a little more.

Maybe more documentation like this would be out of scope for the TS docs. I would think it would be helpful.

@RyanCavanaugh RyanCavanaugh added the Docs The issue relates to how you learn TypeScript label Jun 21, 2021
@orta
Copy link
Contributor

orta commented Jun 22, 2021

A link in our docs to a well commmented playground showing both and letting folks play with the classes (like we do for types vs interfaces ) would probably solve this quite well. Open to PRs on the website 👍🏻

@rpivo
Copy link
Author

rpivo commented Jun 22, 2021

@orta thanks -- I'd be happy to help with this. Will follow up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Docs The issue relates to how you learn TypeScript
Projects
None yet
Development

No branches or pull requests

6 participants