Skip to main content

How to Use Private Class Fields in JavaScript (and Solve the "must be declared" Error)

With the introduction of modern ES2022 features, JavaScript classes can now have truly private fields and methods using the hash (#) prefix. This is a powerful feature for creating robust and secure components. A common error that developers encounter when first using this syntax is the SyntaxError: Private field '...' must be declared in an enclosing class.

This guide will explain the concept of private class fields, show you the correct syntax for declaring and using them, and clarify why this error occurs and how to fix it by interacting with private data through public methods.

The Core Concept: Encapsulation and Private Fields

Encapsulation is a fundamental principle of object-oriented programming. It means bundling the data (properties) and the methods that operate on that data within a single unit (a class), and restricting direct access to an object's internal state.

Private fields (#) are the tool for achieving this. They create "internal-only" variables that cannot be read or changed from outside the class. This prevents accidental manipulation and makes your components safer and easier to use.

The Syntax: Declaring Private Fields and Methods

A private field or method is declared by prefixing its name with a hash (#).

  • Private fields must be declared at the top level of the class body. You cannot declare them for the first time inside the constructor.
class MyClass {
// 1. Private field declaration (must be done here)
#privateField;

// You can also initialize it with a value
#anotherPrivateField = 'initial value';

constructor(value) {
// 2. You can then assign a value to it inside the constructor or other methods
this.#privateField = value;
}

// 3. Private method declaration
#privateMethod() {
return `This is a secret: ${this.#privateField}`;
}

// 4. Public method that can access the private members
getSecret() {
return this.#privateMethod();
}
}

The Core Problem: Accessing Private Fields from Outside the Class

The "Private field must be declared in an enclosing class" error is a SyntaxError, not a ReferenceError. This means the JavaScript engine knows before the code even runs that you are attempting an illegal operation: accessing a private member from outside its class scope.

Example of the problem:

class Person {
#name = 'Alice';
}

const p = new Person();

// ⛔️ SyntaxError: Private field '#name' must be declared in an enclosing class
console.log(p.#name);
note

This error occurs because the #name field is private to the Person class. The code outside of the class has no knowledge of it and is not allowed to access it.

The Solution: Using Public Methods to Access Private Data

The correct way to interact with private data is through public methods (methods without a # prefix). These methods act as a controlled "gatekeeper" to the class's internal state.

Solution:

class Person {
#name;

constructor(name) {
this.#name = name;
}

// A public "getter" method to read the private field
getName() {
return this.#name;
}

// A public "setter" method to change the private field
setName(newName) {
if (newName.length > 0) {
this.#name = newName;
}
}
}

const p = new Person('Alice');

// ✅ Correct: Access the data via the public method.
console.log(p.getName()); // Output: Alice

// ✅ Correct: Modify the data via the public method.
p.setName('Bob');
console.log(p.getName()); // Output: Bob
note

This pattern is the essence of encapsulation. The outside world doesn't need to know about #name; it only needs to know about getName() and setName().

Practical Example: A Counter Class

This example demonstrates a simple Counter class that uses a private field to protect its internal state. The user of this class cannot accidentally set the count to a negative number or a non-numeric value.

class Counter {
// The count is private and can only be modified by the class's own methods.
#count = 0;

increment() {
this.#count++;
}

decrement() {
this.#count--;
}

// A public getter to safely expose the current count.
getCount() {
return this.#count;
}
}

const myCounter = new Counter();
myCounter.increment();
myCounter.increment();
console.log(myCounter.getCount()); // Output: 2

// You CANNOT do this, which protects the state of the counter.
// myCounter.#count = -100; // ⛔️ This would throw a SyntaxError.

Conclusion

The Private field must be declared in an enclosing class error is a feature, not a bug. It is the mechanism by which JavaScript enforces the privacy and integrity of your class's internal data.

  • Declare private members at the top level of a class body using the # prefix.
  • Private members can only be accessed from within the class in which they are defined.
  • Provide public methods (getters, setters, etc.) to allow the outside world to interact with the private data in a controlled manner.

By following these rules of encapsulation, you can write more robust, secure, and maintainable object-oriented code in JavaScript.