TypeScript Access Modifiers

Access modifiers are keywords that control who can read or change a property or method inside a class. TypeScript provides three access modifiers: public, private, and protected. Without them, every property is accessible from anywhere — which leads to bugs in large projects because any part of the code can accidentally change data it should not touch.

The Real-World Analogy

Picture a hospital:

+---------------------------------------------------+
|                   HOSPITAL                        |
|                                                   |
|  Reception (public)  → Anyone can walk in         |
|  Doctor's Office     → Only staff can enter       |
|  (private)                                        |
|  Staff Room          → Staff + trainees allowed   |
|  (protected)                                      |
+---------------------------------------------------+

Access modifiers work the same way for class members — they define which "rooms" are open and to whom.

The Three Access Modifiers

ModifierAccessible FromTypical Use
publicAnywhere (inside class, outside class, subclasses)Data meant to be used freely
privateOnly inside the class itselfInternal data no one else should touch
protectedInside the class + subclasses onlyData shared with child classes but not outsiders

public Modifier

public is the default. Every property and method without a modifier is automatically public.

class Student {
    public name: string;
    public grade: string;

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

    public getReport(): string {
        return `${this.name} — Grade: ${this.grade}`;
    }
}

let s = new Student("Priya", "A");
console.log(s.name);         // Priya  — accessible outside
console.log(s.getReport());  // Priya — Grade: A

private Modifier

A private property exists only inside its own class. No outside code — not even a subclass — can read or change it directly.

class BankAccount {
    public owner: string;
    private balance: number;       // only this class can touch balance

    constructor(owner: string, initialBalance: number) {
        this.owner = owner;
        this.balance = initialBalance;
    }

    public deposit(amount: number): void {
        if (amount > 0) {
            this.balance += amount;
        }
    }

    public withdraw(amount: number): void {
        if (amount <= this.balance) {
            this.balance -= amount;
        } else {
            console.log("Insufficient funds");
        }
    }

    public getBalance(): number {
        return this.balance;   // controlled access through a method
    }
}

let account = new BankAccount("Rakesh", 5000);
account.deposit(2000);
console.log(account.getBalance());  // 7000

// account.balance = 99999;
// Error: Property 'balance' is private

Why private Matters

Without private:
  account.balance = 99999;   // anyone can cheat the system

With private:
  Only deposit() and withdraw() can change the balance
  → The bank's rules are enforced automatically

protected Modifier

protected sits between public and private. Subclasses (child classes) can access protected members, but code outside the class hierarchy cannot.

class Employee {
    public name: string;
    protected baseSalary: number;     // child classes can use this

    constructor(name: string, salary: number) {
        this.name = name;
        this.baseSalary = salary;
    }

    public getDetails(): string {
        return `${this.name} — Base Salary: ₹${this.baseSalary}`;
    }
}

class Manager extends Employee {
    private bonus: number;

    constructor(name: string, salary: number, bonus: number) {
        super(name, salary);
        this.bonus = bonus;
    }

    public getTotalPay(): number {
        return this.baseSalary + this.bonus;   // baseSalary accessible here
    }
}

let mgr = new Manager("Sunita", 80000, 20000);
console.log(mgr.getTotalPay());  // 100000
console.log(mgr.name);           // Sunita (public — fine)

// console.log(mgr.baseSalary);
// Error: Property 'baseSalary' is protected

Access Modifier Diagram

CLASS HIERARCHY ACCESS RULES
─────────────────────────────────────────────────────
              │ Same Class │ Subclass │ Outside Code
─────────────────────────────────────────────────────
public        │    YES     │   YES    │     YES
protected     │    YES     │   YES    │     NO
private       │    YES     │   NO     │     NO
─────────────────────────────────────────────────────

Shorthand in Constructor

TypeScript allows declaring and initializing class properties directly in the constructor parameters. Adding a modifier before the parameter name creates the property automatically.

// Without shorthand — verbose
class Product {
    public name: string;
    private price: number;

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

// With shorthand — clean and short
class Product {
    constructor(
        public name: string,
        private price: number
    ) {}

    public getPrice(): number {
        return this.price;
    }
}

let p = new Product("Laptop", 65000);
console.log(p.name);        // Laptop
console.log(p.getPrice());  // 65000

readonly Modifier

readonly prevents a property from being changed after it is set. It works alongside access modifiers.

class Certificate {
    public readonly studentName: string;
    public readonly issueDate: string;

    constructor(name: string, date: string) {
        this.studentName = name;
        this.issueDate = date;
    }
}

let cert = new Certificate("Ananya", "2026-01-15");
console.log(cert.studentName);   // Ananya
console.log(cert.issueDate);     // 2026-01-15

// cert.studentName = "Someone Else";
// Error: Cannot assign to 'studentName' because it is a read-only property

Practical Example: User Profile Class

class UserProfile {
    public username: string;
    private passwordHash: string;
    protected email: string;
    public readonly userId: number;

    constructor(userId: number, username: string, email: string, password: string) {
        this.userId = userId;
        this.username = username;
        this.email = email;
        this.passwordHash = this.hashPassword(password);
    }

    private hashPassword(password: string): string {
        // simplified — real code uses bcrypt or similar
        return "hashed_" + password.length;
    }

    public checkPassword(password: string): boolean {
        return this.passwordHash === this.hashPassword(password);
    }

    public getPublicInfo(): object {
        return {
            id: this.userId,
            username: this.username
        };
    }
}

class AdminUser extends UserProfile {
    public getEmail(): string {
        return this.email;   // protected — accessible in subclass
    }
}

let user = new UserProfile(101, "rahuldev", "rahul@mail.com", "secret123");
console.log(user.username);          // rahuldev
console.log(user.checkPassword("secret123"));  // true
// user.passwordHash — Error: private

Summary

ModifierDefault?Inherited by Subclass?Usable Outside?
publicYesYesYes
privateNoNoNo
protectedNoYesNo
readonlyNoYesYes (read only)

Leave a Comment

Your email address will not be published. Required fields are marked *