TypeScript Access Modifiers

Access Modifiers are one of the core features of TypeScript object-oriented programming.

They are used to control the visibility of class members (properties, methods, constructors).

Through access modifiers, encapsulation can be achieved, protecting the internal implementation details of a class.


SVG Diagram: Scope of Access Modifiers Background Title Scope of Access Modifiers public Inside class ✓ Subclass ✓ External ✓ protected Inside class ✓ Subclass ✓ External ✗ private Inside class ✓ Subclass ✗ External ✗ Example area Use cases public scenario public Public methods/properties E.g., user name, login method protected scenario protected Methods visible to subclasses E.g., calculation formulas, template methods private scenario private Internal implementation details E.g., database connection, internal calculations

Why Do We Need Access Modifiers?

Encapsulation is one of the three principles of object-oriented programming.

Encapsulation means hiding data and the methods that operate on the data, exposing only the necessary interfaces to the outside.

Access modifiers are the means to achieve encapsulation; they control the visibility scope of class members.

Concept explanation:Access modifiers determine where class members can be accessed. TypeScript provides three access modifiers: public, protected, and private.


public modifier

public is the default access modifier, meaning members can be accessed anywhere.

Whether inside the class, in a subclass, or outside the class, public members can be accessed.

Example

// Define an animal class
class Animal {
    // Use public to modify the name property (can be omitted, public by default)
    public name: string;

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

    // Public speak method
    public speak(): void {
        console.log(this.name + " makes a sound");
    }
}

// Create an instance
var animal = new Animal("Animal");

// Access public property outside the class
console.log(animal.name);

// Call public method outside the class
animal.speak();

Output:

animal
Animals make sounds.

Explanation:If you do not write an access modifier, TypeScript will use public by default. Therefore, public can be omitted, but for code clarity, it is recommended to declare it explicitly.


private modifier

private indicates private members, which can only be accessed inside the class where they are defined.

Neither subclasses nor the outside of the class can access private members.

This is often used to hide the internal implementation details of a class and protect data from accidental modification.

Example

// Define a bank account class
class BankAccount {
    // Use private to modify the balance, accessible only inside the class
    private balance: number;

    // Constructor
    constructor(initialBalance: number) {
        this.balance = initialBalance;
    }

    // Deposit method
    public deposit(amount: number): void {
        if (amount > 0) {
            this.balance += amount;  // Private properties can be accessed inside the class
            console.log("Deposit successful, current balance: " + this.balance);
        }
    }

    // Get balance
    public getBalance(): number {
        return this.balance;  // Private properties can be accessed inside the class
    }
}

// Create an account instance
var account = new BankAccount(1000);

// Deposit
account.deposit(500);

// Get balance through a public method
console.log("Balance: " + account.getBalance());

// Error: private properties cannot be accessed directly outside the class
// console.log(account.balance); // Compilation error!

Output:

存款成功,当前余额: 1500
余额: 1500

Best practice:Setting the internal state of a class to private and providing controlled access through public methods is the standard way to implement encapsulation.


protected modifier

protected indicates protected members, which can be accessed inside the class and in subclasses.

The outside of the class cannot directly access protected members.

This is very useful when you need subclasses to inherit certain functionality from the parent class while hiding implementation details.

Example

// Define a Person base class
class Person {
    // Use protected to modify name, accessible in subclasses
    protected name: string;

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

// Define an Employee class that inherits Person
class Employee extends Person {
    // Department is private
    private department: string;

    constructor(name: string, department: string) {
        super(name);  // Call the parent class constructor
        this.department = department;
    }

    // Self-introduction method
    public introduce(): string {
        // Subclasses can access protected member name
        return "I am " + this.name + ", at " + this.department + " working";
    }
}

// Create an Employee instance
var emp = new Employee("Alice", "Technology Department");

console.log(emp.introduce());

// Error: protected members cannot be accessed outside the class
// console.log(emp.name); // Compilation error!

Output:

我是 Alice,在 技术部 工作

Use cases:protected is often used to define properties that subclasses need to use but should not be exposed to the outside.


readonly modifier

readonly is used to set properties as read-only.

They can only be assigned at declaration or in the constructor, and cannot be modified afterwards.

This is very useful when defining constants or identifiers.

Example

// Define a User class
class User {
    // Properties modified with readonly can only be assigned during initialization
    // User ID
    readonly id: number;
    // Username
    readonly name: string;

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

// Create a User instance
var user = new User(1, "Alice");

console.log("User: " + user.id + ", " + user.name);

// Error: readonly properties cannot be modified
// user.id = 2; // Compilation error!
// user.name = "Bob"; // Compilation error!

Output:

User: 1, Alice

Note:readonly and private do not conflict. You can use readonly and private together; the property can neither be modified nor accessed from the outside.


Parameter Properties

TypeScript provides shorthand syntax for parameter properties.

Access modifiers can be used directly on constructor parameters to automatically create and initialize properties.

Example

// Define a Point class
class Point {
    // Use modifiers directly on constructor parameters
    // Equivalent to declaring properties and assigning values at the same time
    constructor(
        // public modifier: creates public property x
        public x: number,
        // public modifier: creates public property y
        public y: number,
        // private modifier: creates private property z
        private z: number
    ) {
        // The constructor body can be empty; properties are automatically created
    }

    // Calculate the sum of the three dimensions
    public sum(): number {
        // All properties can be accessed inside the class
        return this.x + this.y + this.z;
    }
}

// Create a Point instance
var point = new Point(1, 2, 3);

// Public properties can be accessed from the outside
console.log("x: " + point.x);
console.log("y: " + point.y);

// Call the method
console.log("Sum: " + point.sum());

// Error: private properties cannot be accessed from the outside
// console.log(point.z); // Compilation error!

Output:

x: 1
y: 2
总和: 6

Simplified code:Parameter properties can greatly simplify class definitions, avoiding repetitive declaration and assignment code.


Comparison of Access Modifiers

Below is a comparison of the scope of the three access modifiers.

Modifier Inside class Subclass Outside class (instance)
public ✓ Accessible ✓ Accessible ✓ Accessible
protected ✓ Accessible ✓ Accessible ✗ Inaccessible
private ✓ Accessible ✗ Inaccessible ✗ Inaccessible

Selection suggestions:By default, use private. Use protected when subclass access is needed. Use public when full public access is required.


Notes

  • Default modifier:When no modifier is written, it defaults to public
  • Constructor:Constructors can also use access modifiers to control instantiation permissions
  • readonly combination:readonly can be combined with public, protected, and private
  • Compilation impact:Access modifiers are only checked at compile time and have no effect at runtime

Best practices:Use the most restrictive access modifier whenever possible. Only expose necessary public interfaces, and make internal implementations private or protected.


Summary

Access modifiers are the core tool for TypeScript to implement encapsulation.

  • public:Public access, the default value
  • private:Private, visible only inside the class
  • protected:Protected, visible inside the class and subclasses
  • readonly:Readonly, cannot be modified after initialization
  • Parameter properties:Syntax for simplifying property declarations

Recommendations:Develop the habit of using access modifiers; this is the foundation of writing high-quality TypeScript code.

Other extensions