3 min read

TypeScript Access Modifiers

TypeScript provides access modifiers to control the visibility of class members (properties and methods). This encapsulates data and prevents unauthorized access or modification.

1. public (Default)

By default, all members of a class in TypeScript are public. They can be accessed anywhere (inside the class, in subclasses, and outside the class).

class Animal {
  public name: string; // 'public' is optional here

  constructor(name: string) {
    this.name = name;
  }

  public move(distance: number) {
    console.log(`${this.name} moved ${distance}m.`);
  }
}

const cat = new Animal("Cat");
cat.move(10); // OK
console.log(cat.name); // OK

2. private

Members marked as private cannot be accessed from outside of its containing class, including subclasses.

class Animal {
  private name: string;

  constructor(name: string) {
    this.name = name;
  }
}

class Dog extends Animal {
  bark() {
    // Error: Property 'name' is private and only accessible within class 'Animal'.
    // console.log(this.name); 
  }
}

const dog = new Animal("Dog");
// Error: Property 'name' is private.
// console.log(dog.name); 

3. protected

The protected modifier acts like private, with the exception that members are also accessible within deriving classes (subclasses).

class Person {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }
}

class Employee extends Person {
  private department: string;

  constructor(name: string, department: string) {
    super(name);
    this.department = department;
  }

  public getElevatorPitch() {
    // OK: Can access protected 'name' from subclass
    return `Hello, my name is ${this.name} and I work in ${this.department}.`;
  }
}

const howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());
// Error: Property 'name' is protected and only accessible within class 'Person' and its subclasses.
// console.log(howard.name); 

4. readonly Modifier

You can make properties read-only by using the readonly keyword. Read-only properties must be initialized at their declaration or in the constructor.

class Octopus {
  readonly name: string;
  readonly numberOfLegs: number = 8;

  constructor(theName: string) {
    this.name = theName;
  }
}

let dad = new Octopus("Man with the 8 strong legs");
// dad.name = "Man with the 3-piece suit"; // Error: name is readonly

5. Parameter Properties (Shorthand)

TypeScript offers a shorthand to declare and initialize a class member in one place by adding an access modifier to the constructor parameter.

class User {
  // Instead of declaring 'name' above and assigning it in the body...
  constructor(public name: string, private age: number) {
    // No body assignment needed!
  }
}

const user = new User("Alice", 30);
console.log(user.name); // Alice
// console.log(user.age); // Error: age is private

6. TypeScript private vs JavaScript #private

TypeScript's private is a compile-time check. At runtime (in the generated JavaScript), the property is just a normal property and can be accessed if you ignore type checking.

Modern JavaScript (ES2020) introduced Private Fields using the # syntax, which guarantees hard runtime privacy.

class Container {
  private tsPrivate = "I am hidden at compile time";
  <a href='/?search=%23jsPrivate' class='obsidian-tag'>#jsPrivate</a> = "I am hidden at runtime";

  print() {
    console.log(this.tsPrivate);
    console.log(this.#jsPrivate);
  }
}

const c = new Container();
// (c as any).tsPrivate; // Works at runtime (though TS complains)
// (c as any).#jsPrivate; // Syntax Error / Runtime Error: Private field '#jsPrivate' must be declared in an enclosing class

programming/javascript/typescript/typescript