Use TypeScript’s private when you want the compiler to discourage accidental access and need ordinary JavaScript properties; use ECMAScript #private when the field must remain inaccessible through normal runtime property access. Neither is universally better: the right choice depends on the privacy boundary, inheritance design, JavaScript target, and—if speed matters—the behavior of your compiled code in its actual runtime.
What is the difference between TypeScript private and #private?
TypeScript’s private modifier restricts access during TypeScript type checking. It does not turn the emitted JavaScript property into a runtime-private field. ECMAScript #private elements, by contrast, are enforced at runtime and are not ordinary string-named properties.
As an Amazon Associate I earn from qualifying purchases.
| Concern | TypeScript private |
ECMAScript #private |
|---|---|---|
| Where privacy applies | Type checking; the emitted property is an ordinary JavaScript property. | Runtime-enforced privacy for the declaring class. |
| External bracket access | TypeScript documents bracket notation such as instance["secretKey"] as an escape hatch in applicable cases; JavaScript can access the ordinary property. |
Bracket notation does not access the private element; #name is a private identifier, not a property key. |
| Same-spelled member in a subclass | Ordinary properties can collide: a subclass property can replace the effective value of a base-class property. | Each class’s private name is scoped to that class, so same-spelled private names are distinct. |
| Older JavaScript targets | Supported by TypeScript even for older targets, including ECMAScript 3, according to the TypeScript 3.8 release notes. | TypeScript 3.8 release notes state that support requires an ES2015 (ES6) or later target; output for lower targets uses a WeakMap-based approach. The current handbook describes WeakMap output when compiling to ES2021 or lower. |
| Performance | Ordinary property access. | Runtime privacy checks or downleveled WeakMap output may affect performance; the documentation establishes no universal speed winner. |
For the documented behavior, see the TypeScript 3.8 release notes and the current TypeScript Classes handbook.
When is TypeScript private the better choice?
When the boundary is for checked TypeScript code
Choose private when your goal is to prevent accidental access by callers working in TypeScript, not to make the property inaccessible to JavaScript at runtime. It can be useful when you want internal implementation details kept out of the normal typed interface while still allowing deliberate workarounds.
#1 Best Overall
The handbook documents bracket notation as an escape hatch for TypeScript private, including cases where tests need access to an internal member. Treat that as a deliberate compromise: it can help with testing or temporary consumer workarounds, but it does not provide hard privacy. See the handbook’s Classes section.
When you need ordinary properties or broader target compatibility
An ordinary property may be the practical option when your project must compile for older JavaScript targets. The TypeScript 3.8 release notes say TypeScript private works even with an ECMAScript 3 target, while TypeScript’s #private support requires ES2015 (ES6) or later. The emitted form also depends on compiler settings: the current handbook says targets of ES2021 or lower use WeakMaps for downleveled private elements.
Rank #2
- TypeScript implements a superset of syntax for strictly typed development, facilitating deep static analysis and enhanced development environment integration. The compiler translates source into standard script formats, ensuring parity across any runtime.
- TypeScript is ideal for front-end developers, full-stack engineers, and software architects who build large-scale web applications. It serves those looking to improve code excellence, reduce bugs through static checking, and maintain complex projects more.
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
Check the project’s TypeScript target and inspect the generated JavaScript before deciding. A source-level declaration alone does not tell you the exact runtime implementation.
When should you choose #private?
When runtime access must be blocked
Use #private when external JavaScript code should not read or write an internal field through ordinary property access, or when you want to avoid exposing an internal name as an accidental API. Unlike TypeScript private, it cannot be reached through a normal bracket-notation workaround. TypeScript’s explanation of this distinction is in the 3.8 release notes.
When base and derived classes need the same internal name
Ordinary same-named properties can collide in an inheritance hierarchy: a subclass declaration can replace the effective value of the base class’s property. Private identifiers avoid that collision because each #name belongs to its declaring class. This is useful when both classes need an implementation detail with the same spelling, without making the names part of a shared property surface.
When methods, accessors, or brand checks are part of the design
TypeScript 4.3 added support for ECMAScript #private methods and accessors as well as fields. TypeScript 4.5 added #field in object checks: a successful check establishes that the object carries that class’s private field and can narrow the value accordingly. These are language capabilities, not substitutes for choosing a privacy boundary. See the TypeScript 4.3 release notes and TypeScript 4.5 release notes.
Does #private make sensitive data secure?
It provides hard runtime privacy for class elements, but a field modifier is not a general security boundary against an attacker who can control the process. The TypeScript handbook advises using mechanisms that offer hard runtime privacy when protection from malicious actors is required; it also notes potential performance effects. For sensitive information, define the threat model and use suitable application-level security controls rather than treating either modifier as encryption or access control for the whole program.
Are private and #private faster?
There is no universal performance winner established by the TypeScript documentation. Ordinary properties use ordinary property access, while runtime privacy checks and downleveled WeakMap implementations may affect speed in some runtimes. If performance is material, benchmark the compiled output on the runtime and configuration you will deploy; do not assume that a general claim applies to your workload.
Best Value
Does TypeScript private affect type compatibility?
Do not confuse runtime privacy with TypeScript’s rules for whether types are compatible. The handbook’s type compatibility guidance says that private and protected members affect assignment compatibility based on the class declarations from which they originate. That is a type-system rule, not evidence that a TypeScript private property is hidden from JavaScript at runtime. See Type Compatibility.
Quick Recap
How to choose for a project
- Decide what “private” must mean. If the goal is to prevent accidental access in checked TypeScript, consider
private. If ordinary runtime access must fail, consider#private. - Check the consumers and tests. If JavaScript callers or tests need a deliberate path to an internal property, understand that TypeScript
privatepermits a softer boundary. Do not choose it while assuming runtime enforcement. - Review inheritance. If a base and subclass need an internal member with the same spelling,
#privategives each class its own private name. - Verify the build target and output. Check the TypeScript
targetand inspect emitted JavaScript, especially if supporting older environments or relying on downleveling. - Measure only if speed matters. Compare the actual compiled forms in the target runtime instead of relying on a blanket performance claim.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




