Background
In TypeScript, private properties were initially implemented using the private modifier, and starting from ECMAScript 2021, JavaScript supports true private fields with the # symbol. The main goal is data encapsulation to protect the internal details of the class from external access.
Problem
The private modifier in TypeScript provides privacy only at the compile time, but in the compiled JavaScript, these fields remain accessible through direct access to object properties. This can lead to unintended modifications of the object state. ES Private Fields (#) are completely inaccessible from outside the class even at the runtime level of JS, providing real data protection.
Solution
TypeScript supports both approaches. When choosing between them, consider the required level of protection and compatibility constraints with JS versions.
Code example:
class Example { private hidden: number; #trulyHidden: string; constructor() { this.hidden = 42; this.#trulyHidden = 'secret'; } getHidden() { return this.hidden; } getTrulyHidden() { return this.#trulyHidden; } } const x = new Example(); // x.hidden — error in TS, but will work via x['hidden'] in JS // x.#trulyHidden — syntax error even in JS
Key features:
private guarantees privacy only at the compile stage of TypeScript#field provides real privacy at the execution level of JavaScript# requires support for modern JS (ES2021+)Can you access a private field of a TypeScript class by direct access in JS?
Yes, you can, as privacy is only implemented at compile time. In the original JS, the field will be a regular object property. For example:
class A { private x = 1; } const a = new A(); console.log((a as any)["x"]); // 1
Can private fields with # be used in interfaces or described using type?
No, #private fields are part of the class implementation only and cannot be described in interfaces, types, or used outside the class itself. Interfaces only describe public members.
Can private fields declared with # be inherited?
No, such fields are not accessible to subclassing classes at all. Only the class itself has access to them:
class Parent { #foo = 123; } class Child extends Parent { // this.#foo = 444; // Error }
private to protect critical data — leads to vulnerabilities with direct accessIn a project for storing passwords in the User class, a private password field was used. One of the developers accidentally accesses it via user['password'] for debugging, and the field gets modified by an external module.
Pros:
Cons:
A developer uses the ES private field #password. Now attempts to access the field through indexing or in subclasses do not go through, ensuring data security even when using third-party libraries and tools.
Pros:
Cons: