TypeScript Classes
TypeScript builds on JavaScript classes with access modifiers, readonly properties, and interfaces so you can enforce object shapes at compile time.
Access Modifiers
JavaScript classes have no built-in concept of private state that the compiler enforces (aside from the newer # syntax). TypeScript adds public, private, and protected keywords that control which code is allowed to read or write a property, catching accidental external access before your code runs.
public, private, and protected
class BankAccount {
public owner: string;
private balance: number;
protected accountType: string;
constructor(owner: string, balance: number) {
this.owner = owner;
this.balance = balance;
this.accountType = "standard";
}
public deposit(amount: number): void {
this.balance += amount;
}
public getBalance(): number {
return this.balance;
}
}
const acc = new BankAccount("Ravi", 100);
acc.deposit(50);
console.log(acc.getBalance());
// acc.balance; // Error: 'balance' is private- public — accessible from anywhere; this is the default if you omit a modifier.
- private — accessible only inside the declaring class, not subclasses or outside code.
- protected — accessible inside the declaring class and any class that extends it.
- readonly — can be set once in the constructor and never reassigned afterward.
Readonly Properties
The readonly modifier protects a property from being reassigned after construction, which is useful for values that should stay fixed for the lifetime of an object, like an id or a creation timestamp.
Using readonly
class Invoice {
readonly id: string;
readonly createdAt: Date;
amount: number;
constructor(id: string, amount: number) {
this.id = id;
this.createdAt = new Date();
this.amount = amount;
}
}
const inv = new Invoice("INV-001", 250);
inv.amount = 300; // fine
// inv.id = "INV-002"; // Error: id is readonlyImplementing Interfaces
An interface describes the shape a class must have without providing any implementation. When a class uses implements, the compiler checks that every member listed in the interface is actually present with a compatible type, which is a great way to enforce a contract across multiple classes.
implements Keyword
interface Shape {
area(): number;
perimeter(): number;
}
class Rectangle implements Shape {
constructor(private width: number, private height: number) {}
area(): number {
return this.width * this.height;
}
perimeter(): number {
return 2 * (this.width + this.height);
}
}
const rect = new Rectangle(4, 5);
console.log(rect.area(), rect.perimeter());Exercise: TypeScript Classes
What does marking a class field as `private` do?