-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
The future of the "private" keyword #31670
Comments
I would personally prefer to keep the When I found out |
Our current plan is to leave the current Reasons for this:
As for a transformer, probably not? It's simple to replace these with a regex if you're motivated. |
Oh the other interpretation of "transformer" would be "Would TS emit |
FWIW I don’t find the type-directed emit argument that strong in this case; it’s a stretch to call
I found this way funnier than I should have, I think. |
On a related note, it’s good to know I’m not the only person who thought I had been dropped into Bizarro World when I first found out about the |
Remember that private fields allow cross-instance access. Consider something like this: class A {
private y = 0;
method(arg: A) {
console.log(arg.y);
}
} The "correct" |
Yeah, I see what you mean now, basically |
Other sometimes-advantages of OG |
Hi I was pointed to this thread by folks regarding the runtime performance concerns mentioned in #31670 (comment). (For some background, I implemented private fields in V8)
Can you expand on this? My understanding is that typescript private is downleved to public property access. AFAIK, the extra overhead for ES private is just one machine load for loading the |
A few more questions that weren't asked yet (it seems):
|
class Foo {
bar: string;
#baz: number;
}
const foo: Foo = { bar: 'bar' }; or is |
I over-extrapolated; I'll trust your assessment on this. I've updated the comment to be more accurate. |
Yes,
Yes
No
The visibility of a method doesn't change which properties it's allowed to access
No. The given object is not a substitute for |
I’m not sure I understand the rationale of this; for TS-private this makes sense because of JS interop (the “private” property is actually public from JS POV); for Is there a case I’m missing where the above substitution wouldn’t be safe? edit: Wait... I bet it’s the cross-instance case again, right? |
Private fields seem like they’d require a nominal, not structural, type, since they’re like a brand. |
|
Just to clarify the cross-instance thing: class Foo {
bar: string = '';
#baz: number = 0;
check(other: Foo) {
console.log(other.#baz);
}
}
const foo: Foo = { bar: 'bar', check: (other: Foo) => undefined };
const realFoo = new Foo();
// Runtime error
realFoo.check(other); |
That shouldn't be allowed, right? |
No, that’s totally normal in most OO languages in my experience - a class can freely access private members of other instances of itself. Same goes for the proposed |
@RyanCavanaugh Though it seems easy to replace TS Then some thought about I understand why TS team decide to support both There would at least three options:
When some programmers/teams with difference preference work together there would be arguments, again and again. Note, TS private and Such arguments would be a bit like the holy war of Tab vs Space, both side have valid reasons but in the engineering viewpoint they are trivial. Unfortunately, not like tab/space which can be converted seamlessly, I hope TS team could have a long-term view about this issue. We should not force the programmers and the whole ecosystem to take the cost of two mechanism. I understand the current situation is largely caused by TC39. The design of TypeScript, as the downstream of the design of ECMAScript, is forced to face such dilemma (not only private field, but also potential big breaking changes due to public fields). As class fields proposal already stage 3, it's very impossible to ask TC39 guys to revisit the issues. But I always think it's wrong to transfer the ten people cost of committee to millions people cost of the whole community. |
As long as Microsoft's own tooling uses TypeScript-based language services also for regular JS, you don't really have the luxury of only supporting one. If you want to settle on using only one, then the best case scenario is to support only one at a time. That is: Anything else is either going to piss off TS developers or JS developers. |
I love the fact that TypeScript's So as annoying as it may seem, I'm glad it does not conflict with existing TypeScript syntax. I believe that TypeScript should continue to maintain "soft private" via |
Private things aren’t supposed to be tested; you can use symbols for “soft private”. |
@ljharb To be more clear, I don't mean directly testing private "things", I'm talking about unit testing public things (methods). There is a huge benefit in having access to To that end, both approaches (TS's |
Symbols created with The same when using It's possible to pass an instance of something from Copy # 1 to copy # 2 and then stuff breaks during run-time. I wonder if this private thing will also break this way... |
@AnyhowStep yes, it will - different instances will have different private fields, just like as if a closed-over WeakMap was being used. |
That kind of thing is exactly why |
What do you think, how many people will use it # feature in day to day practice? If the majority of them then it's not ready, because it's in dissonance with all other "private", "public", "protected". If it's only a very rare case, then please, put it somewhere away from regular "private", "public", "protected" in the handbook to prevent people's confusion. |
My only gripe with class Foo {
#x //GitHub unhelpfully gives me an annoying dropdown
} Can I join the committee and reject the proposal because of GitHub inconvenience? Okay, one more joke. Rights, class Human {
#rights;
removeRights () {
console.log("No");
}
}
class Government {
takeawayRights (human) {
human.removeRights(); //No
human.rights = undefined; //Not allowed
}
} vs Privileges, class Human {
private privileges;
removePrivileges () {
console.log("No");
}
}
class Government {
takeawayPrivileges (human) {
human.removePriveleges(); //No
human.privileges = undefined; //OK!
}
} |
I think people are too optimistic in this topic ^_^ , the interesting part is the fans of TS normally in the other side, that's why they choose TS which can provide more protection than JS. Unfortunately the great success of TS also cause many ignorance of JS, many TS programmers just say: I don't care about JS any more, I just use TS!
All these examples are just stylistic which I don't think comparable to this issue. Actually it's very dangerous that people think
Understanding the difference of two incompatible private mechanism is definitely a burden. Especially
I really hope TS documentation could add caveat for that.
The problem is , classes is very different than other language features, there is inheritance. Base classes and derived classes could in different packages. In many cases, you can't control the upstream and downstream of your classes. So there is no easy way to truly avoid mixing of
"Pick one" is easy to say but the cost of discussion/arguments/conflict/postmortem/refactoring of "pick one" will be paid by every team, every project, again and again. As I always say, we TC39 are transferring 100 people committee cost to 10,000,000 people community cost.
Actually it's very hard to understand all the consequence of Anyway I am just the "people are overthinking this." But again, we will see what happened. |
@mbrowne Unfortunately, when something is broadly used in production, it will be too late to remove it even it is heavily flawed. So it's meaningless to make "decision" that time. Actually we are now in the way to such situation. And there is a logic problem that "feedback from people who have actually used private fields in production". We the frontend branch of tech committee of 360 tech group (consist of 10+ most experienced programmer, team leaders and architects of our group, most of them have 10+ years JS experience and at least half of them are heavy TS developers) already discussed the feature thoroughly, we have the conclusion that class fields have serious problems and we will never use it in our production code. Class fields is not a small feature, and several issues of them are interoperable issues with other code in complex context which will be very hard to track, we have no interest to take any risk to test it in our production code. But as your criteria, our opinion is not valid feedback because we didn't use it in production. The problem is if we already anticipate the worst result, why we want to use it in production? |
@hax We could have a long discussion about process issues, but since this is the TypeScript repo, I'll just say that I do think the feedback of those who have investigated the feature but not used it in production is valuable (especially if they have investigated it deeply as you have done), but should definitely be considered together with feedback from usage in production. And we certainly saw some flaws in the current TC39 staging process with this feature that should be addressed in order to collect more real-world feedback (e.g. via Babel) before new features ship in browsers. But I would ask TS users to keep JS users in mind here...JS users have wanted private state in their classes for a long time. The only other syntax I have seen that would allow for hard privacy at run-time (which I don't see as a requirement—I would be fine with soft run-time privacy—but many people do want it, including some TS users) is var/let/const syntax as in the classes 1.1 proposal and rdking's fork of that proposal. And personally, I think that TC39 is correct that that syntax is actually more confusing and problematic than the class fields ( |
You forgot the very probable option
|
Like many here, I dislike the Since |
I don't get the point why it would be a breaking change to have a tsconfig flag "compilePrivateToHashtag" which is disabled by default. With the flag turned (by default) off the behaviour remains the same; no breaking change. But If you like to have hard privacy enabled by using the pirvate key word instead of the # syntax your are free to set the flag. This solution would fit all needs: With optionally tslint enabled to prefer one syntax over the other. |
Why should anybody be given the ability to write new code that is nonstandard? The language has no private keyword and won’t have one; new code shouldn’t have one either. |
JavaScript has no access modifier keywords. But it doesn't have - e.g. type declarations either. That's why TypeScript is a superset. There's no reason TypeScript shouldn't be allowed to map its |
It is a fair criticism to say: "you should use |
There’s no value in using TS’s private keyword semantics when the #, alone, conveys “private”, in a standard way. |
We're not going to add a flag for this. I know some people have aesthetic aversion to |
It could still be nice to have an option to make |
Is it planned in the future to transpile (tsc) directly to #variable / #method instead of using a WeakMap ? |
If we're compiling for a es2021 target, shouldn't a true |
The handbook states:
I'm not sure why private fields didn't make it into the ES2021 target, but in any case it seems that the only way to get TS to output native private fields at the moment is to use
|
Because class fields are in ES2022: https://github.com/tc39/proposals/blob/main/finished-proposals.md |
I believe that's out of scope of TypeScript's goals (essentially the goal is to avoid producing new runtime language features, and make only strippable type syntax on top of standard JavaScript), but compiling |
This is a somewhat "catch-all" issue to serve as a place of discussion for a question that is sure to come up given the advancement of Private-Named Instance Fields:
What is the future of the "private" keyword in TypeScript?
That's the general question - following are some short-and-sweet Q&As that I've pulled up for visibility.
Is TypeScript going to depreciate it, and aim towards phasing it out in favor of the private field operator?
Is it going to be supported in the form of a transformer , turning
private bar
into#bar
?A few more questions:
Would #-fields allow modifiers like readonly?
Will public #x, private #x and protected #x be an error?
Will it be possible to assign #-fields from the constructor parameters, the same way as the current parameter-properties work (i.e., constructor (private x) and constructor (#x))?
What visibility rules will apply between private entities and #-entities? What if I use a private-entity from a #-entity, or vice versa? Seems that #-entites are 'more' private than private-entities, in some sense. :)
Would it be possible to do the following:
The text was updated successfully, but these errors were encountered: