Access Modifiers
Learn how public, private, protected, and readonly control the visibility of class members.
Reading Time
14 min
Lesson
Lesson 17 of 30
What Are Access Modifiers?
Access modifiers control where a class member can be accessed from — the class itself, its subclasses, or anywhere. TypeScript enforces them at compile time.
Access Modifiers
| Modifier | Accessible From |
|---|---|
| public (default) | Anywhere — the class, subclasses, and outside code |
| private | Only within the declaring class itself |
| protected | The declaring class and its subclasses, but not outside code |
| readonly | Can be combined with any of the above; prevents reassignment after construction |
public, private, and protected
class BankAccount {
public accountHolder: string;
private balance: number;
protected accountNumber: string;
constructor(accountHolder: string, balance: number, accountNumber: string) {
this.accountHolder = accountHolder;
this.balance = balance;
this.accountNumber = accountNumber;
}
deposit(amount: number): void {
this.balance += amount; // OK: inside the class
}
}
const account = new BankAccount("Alice", 1000, "ACC-001");
account.balance; // Error: 'balance' is privateprotected in Subclasses
A protected member is hidden from outside code but remains accessible to any class that extends the declaring class, useful for internal details that subclasses still need.
protected Accessible in a Subclass
class SavingsAccount extends BankAccount {
showAccountNumber(): string {
return this.accountNumber; // OK: protected, accessible in a subclass
}
}Native JavaScript Private Fields
JavaScript itself now supports true private fields with a # prefix, which are enforced at runtime, not just compile time — unlike TypeScript’s private keyword, which is erased when compiled.
Native # Private Fields
class Counter {
#count = 0;
increment(): void {
this.#count++;
}
get value(): number {
return this.#count;
}
}
const counter = new Counter();
counter.#count; // Error, and also fails at runtime — truly inaccessibleTypeScript private is Compile-Time Only
Because TypeScript’s private is erased during compilation, the compiled JavaScript output has no real enforcement — code that bypasses the type checker (or plain JavaScript consumers) can still access it at runtime.
Best Practice
Reach for native # private fields when you need genuine runtime privacy (like a library’s internal state), and TypeScript’s private/protected for everyday encapsulation within your own typed codebase.