Repository navigation
Closed
Labels
DiscussionIssues which may not have code impactIssues which may not have code impact
Description
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?
Our current plan is to leave the current private behavior as-is.
Is it going to be supported in the form of a transformer , turning private bar into #bar?
definitely "no" because that would require type-directed emit.
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. :)
The visibility of a method doesn't change which properties it's allowed to access
Would it be possible to do the following:
class Foo {
bar: string;
#baz: number;
}
const foo: Foo = { bar: 'bar' };
Reacted by Aleksey Levenstein, Francisco Dias, Piotr Łukomiak, Karol Majewski, Daniel Meyer, Mattias Buelens, Jean-Franck, Ashlynne Mitchell, Chris Yungmann, Huachao Mao and 20 more
Reacted by Abraham White, Basarat Ali Syed, Piotr Lewandowski, Stefan Schult, Michał Michalczuk, Andrii Dieiev, Karol Majewski, Nicholas Jamieson, Gareth Jones, Albert Mañosa and 1 more
Metadata
Metadata
Assignees
Labels
DiscussionIssues which may not have code impactIssues which may not have code impact
Activity
AnyhowStep commentedon May 30, 2019
I would personally prefer to keep the
privatekeyword. To me, it looks waywayway better than#. And is more clear in its intent, to me. And I wouldn't want to have to go back and do a regex replace forprivateto#.When I found out
#was being proposed instead of justprivate, I thought I was experiencing the Mandela effect.RyanCavanaugh commentedon May 30, 2019
Our current plan is to leave the current
privatebehavior as-is.Reasons for this:
privateprivatefields can be read from unit tests (I realize some people find this personally distasteful, but this is not universal)#syntax so why force it on themWeakMap(which not all runtimes have) there's no good equivalent downleveling for hard runtime privacyAs for a transformer, probably not? It's simple to replace these with a regex if you're motivated.
RyanCavanaugh commentedon May 30, 2019
Oh the other interpretation of "transformer" would be "Would TS emit
privateas#", the answer to which is definitely "no" because that would require type-directed emit.fatcerberus commentedon May 30, 2019
FWIW I don’t find the type-directed emit argument that strong in this case; it’s a stretch to call
private“type info” IMO (also we’re emitting the class itself, so we could just say it’s an alias for#and thus not really type info at all). That said, changing TS to emit private members as#would be a massive, massive breaking change (at runtime too!), so that’s plenty good reason to avoid going that route as far as I’m concerned.I found this way funnier than I should have, I think.
fatcerberus commentedon May 30, 2019
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
#sigil.RyanCavanaugh commentedon May 30, 2019
Remember that private fields allow cross-instance access. Consider something like this:
The "correct"
#-based emit of this would require type information onargin order to detect thatyshould be rewritten to#yfatcerberus commentedon May 30, 2019
Yeah, I see what you mean now, basically
obj.foois ambiguous without type info if there’s a possibility it can “really mean”obj.#foo. Thanks, hadn’t thought of the cross-instance case.mheiber commentedon May 31, 2019
Other sometimes-advantages of OG
privateis thatprivatefields show up inJSON.stingifyoutput and can show up inconsole.log.gsathya commentedon May 31, 2019
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
PrivateNamebacking the property when compared to public property access. I don't expect this to be of significant runtime overhead. Is there something else?zhuravlikjb commentedon May 31, 2019
A few more questions that weren't asked yet (it seems):
readonly?public #x,private #xandprotected #xbe an error?constructor (private x)andconstructor (#x))?privateentities 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. :)Thanks.
nicojs commentedon May 31, 2019
or is
#bazpart of the shape ofFoo? (hopenotso).RyanCavanaugh commentedon May 31, 2019
I over-extrapolated; I'll trust your assessment on this. I've updated the comment to be more accurate.
RyanCavanaugh commentedon May 31, 2019
Yes,
readonlyis meaningful inside the classYes
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
Foo; the same reasoning about cross-member access requiringprivatemembers to be present applies herefatcerberus commentedon May 31, 2019
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
#fields, only the class itself can access it, even at runtime, and therefore as long as the rest of the shape matches, it should be fine from a duck-typing POV.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?
53 remaining items
trusktr commentedon Dec 17, 2023
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
privateto soft privacy using symbols, under an option, would in fact be pretty sweet.ArrayIterator commentedon Oct 23, 2025
2025! the private visibility modifier can be dangerous on some case, eg : doing Stringify object, the private modifier can be exposed on JSON.
Finesse commentedon Mar 19, 2026
There is something gained. The #-fields can be shortened easily, similar to how function, class and variable names are minified. Tools like Terser replace long #-names with short garbage. This gives 2 advantages:
Do you have other options for achieving these goals? Replacing all
privatefields with #-fields in the source code is a solution, but it's awkward for multiple reasons. Havingtscdo a prepending of#to the private fields is such a simple and elegant solution, that I'm surprised it hasn't been implemented yet. I call it simple, because it can be done in a file using just the content of that file. That is, it doesn't violateisolatedModules.Why is it allowed for
const enum? It's also an elegant solution for source code concealing and code size deduction. What's the key difference?snarbles2 commentedon Mar 19, 2026
It really, really isn't that simple.
privateand#have different semantics. Transpiling the former to the latter can break things in all kinds of ways.You would have to change the meaning of
private, but the (subjective) upsides of having a "soft-private" and backwards compatibility concerns make for a rather strong argument against doing so, to put it mildly.You could argue for having a compiler switch, but if people find it confusing that
#andprivatemean similar but not identical things, you're not doing the world favors by adding into the mix thatprivatecould mean two different things depending on compiler version or settings.It is grandfathered in, a vestige from before TypeScript adopted the position against type-directed emit.
irfanstract commentedon Aug 14, 2026
so we should start warning against
privateand call for rewrite.certain transpiler(s) drop
constand treat them like plainenummaybe?RyanCavanaugh commentedon Aug 17, 2026
You can add a lint rule if you don't want to use
private. We're not going to break huge amounts of code for a "warning" that doesn't do anything.ljharb commentedon Aug 17, 2026
What about a tsconfig option that removes it entirely?
snarbles2 commentedon Aug 17, 2026
Why would you want to remove it? It has well understood semantics that can be useful. I'm not sure any of the considerations that factored into to the current state of affairs have changed meaningfully.
RyanCavanaugh commentedon Aug 17, 2026
Why have a flag for banning
privatevs any other syntactic feature you might not like? I don't get the distinctionrjgotten commentedon Aug 17, 2026
Why have a flag for banning
anythen?privatearguably does more real-world harm thanany- given private isn't actually private and the corpus of code written by neophytes with wrong expectations about it.ljharb commentedon Aug 17, 2026
Ryan Cavanaugh (@RyanCavanaugh) there's a large qualitative difference between banning a type-space syntax and banning a value-space syntax, especially one that will never be standard, and whose emit provides false encapsulation.
snarbles2 none of its semantics are useful - if you want truly private data, use JS private fields; if you don't, just use symbols or strings (like, a leading underscore, or whatever).
privateis no different than the latter.snarbles2 commentedon Aug 18, 2026
Certainly not true. There are things you can do with
privatethat you can't with#private, andprivateis still compiler enforced. This even comes up in vanilla JS, where you have to resort to _prefixes.You can use symbols for that purpose, I suppose, but I have a hard time buying that I should sacrifice ergonomics/readability to satisfy somebody else's notion of what's "right".
I'm usually the last person to make this suggestion, but a linter is the right solution here.
mbrowne commentedon Aug 18, 2026
One thing that might help would be to say that the
privatekeyword is deprecated in the official docs. Obviously it won't ever be removed because of the need to preserve backward compatibility, but it's non-standard and IMO it would make sense to officially deprecate it given native private and other options available.rjgotten commentedon Aug 18, 2026
And you can only do those things because
privateis misnamed and actually at runtime is anything-but.An option in the compiler to disallow
private- pretty much the same as the one that disallowsany- for all intents and purposes is a linter option.I would be all for TypeScript inventing a syntax for symbol usage that could desugar properly without runtime surface as well as make
unique symboleasier to stomach within the typing system. Because woo-boy is that a pain in the dot-dot-dot to work with...