TypeScript

Modifiers, Public, Protected, Private in Typescript

Access modifiers control who can see and use a class member. TypeScript gives you three: public, protected, and private. Each draws a different boundary.

15 Apr 2024

Modifiers, Public, Protected, Private in Typescript

Access modifiers control who can see and use a class member. TypeScript gives you three: public, protected, and private. Each draws a different boundary.

The three levels

Public — accessible from anywhere. This is the default. If you don't specify a modifier, it's public.

Protected — accessible inside the class and its subclasses. Not accessible from outside code.

Private — accessible only inside the class that defines it. Not even subclasses can touch it.

Typescript
class Person {
  public name: string;
  protected age: number;
  private email: string;

  constructor(name: string, age: number, email: string) {
    this.name = name;
    this.age = age;
    this.email = email;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

What happens in a subclass

A subclass can access public and protected members. private members are off limits.

Typescript
class Employee extends Person {
  constructor(name: string, age: number, email: string) {
    super(name, age, email);
  }

  showDetails() {
    console.log(`Name: ${this.name}, Age: ${this.age}`); // works
    console.log(`Email: ${this.email}`); // Error: 'email' is private
  }
}

What happens from outside

Typescript
const person = new Person('Alice', 30, 'alice@example.com');

console.log(person.name);  // works
console.log(person.age);   // Error: 'age' is protected
console.log(person.email); // Error: 'email' is private

The trade-off

Access modifiers enforce encapsulation at compile time. They prevent accidental coupling to internal state. That's the benefit.

The cost: this is compile-time only. At runtime, JavaScript has no concept of protected. Anyone with access to the object can still reach any property. TypeScript's private is a guardrail, not a wall.

If you need true runtime privacy, use JavaScript's # private fields instead. But for most codebases, TypeScript's modifiers are enough to keep the architecture clean.

Keep reading