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
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
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
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
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
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
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
Other extensionsRecommendations:Develop the habit of using access modifiers; this is the foundation of writing high-quality TypeScript code.