Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

ECMAScript private fields are a native JavaScript feature, fully supported in TypeScript, that provides strict, parse-time and runtime-enforced encapsulation for class members. By prefixing a class property, method, or accessor identifier with a hash symbol (#), the member becomes completely inaccessible outside the lexical scope of its containing class body.
class Container {
    // Declaration of an ECMAScript private field
    #internalState: number;

    constructor(initialState: number) {
        this.#internalState = initialState;
    }

    // Declaration of an ECMAScript private method
    #compute(): number {
        return this.#internalState * 2;
    }

    public getResult(): number {
        return this.#compute();
    }
}

Technical Characteristics

Strict Enforcement Unlike TypeScript’s private modifier, which is a compile-time only construct erased during JavaScript emission, ECMAScript private fields (#) guarantee hard privacy. Attempting to access a # field outside its class results in a SyntaxError in JavaScript. Because this is a parse-time error, it prevents the script from executing entirely. Furthermore, the field cannot be inspected using standard property enumeration (e.g., Object.keys()) or reflection. No Dynamic Access Private fields cannot be accessed dynamically using bracket notation. The identifier must be statically known and accessed via dot notation within the lexical scope of the class. Attempting to use bracket notation with a string literal does not interact with the private field at all; it merely attempts to access a standard public property whose string key happens to include a hash.
const instance = new Container(10);

// TypeScript Compile-time Error: Property '#internalState' is not accessible outside class 'Container'.
// JavaScript Parse-time Error: SyntaxError: Private field '#internalState' must be declared in an enclosing class.
instance.#internalState; 

// TypeScript Compile-time Error: Property '#internalState' does not exist on type 'Container'.
// JavaScript Runtime: Valid syntax, but evaluates to `undefined`. It attempts to access a public property with the string key "#internalState", bypassing the private field entirely.
instance['#internalState']; 
Inheritance and Shadowing ECMAScript private fields are strictly bound to the class that declares them. They are invisible to subclasses. If a subclass declares a private field with the exact same name as a parent class, it creates a distinct, unique slot in memory rather than overriding or shadowing the parent’s field.
class Base {
    #id = "base_id";
    
    printBaseId() {
        console.log(this.#id);
    }
}

class Derived extends Base {
    // This is a completely separate field from Base's #id
    #id = "derived_id"; 
    
    printDerivedId() {
        console.log(this.#id);
    }
}

Compilation and Target Environments

TypeScript’s handling of ECMAScript private fields depends on the target specified in the tsconfig.json:
  • ES2022 or higher: TypeScript emits the native # syntax directly into the compiled JavaScript.
  • ES2015 to ES2021: TypeScript downlevels the private fields using WeakMap instances to simulate strict runtime privacy without leaking memory.
  • Below ES2015 (e.g., ES5): ECMAScript private fields are not supported, and compilation will fail, as WeakMap is required for polyfilling the behavior.
Master TypeScript with Deep Grasping Methodology!Learn More