TypeScript classes in practice — parameter properties, access modifiers, inheritance with checked override, and abstract classes.
Why: public, private, and protected control who can touch a member; readonly blocks reassignment. Putting a modifier on a constructor parameter declares AND assigns the field in one line — the most idiomatic TS class pattern.
class BankAccount {
// Each modified parameter becomes a field automatically
constructor(
public readonly owner: string,
private balance: number,
protected currency = 'USD',
) {}
deposit(amount: number) {
this.balance += amount; // private — fine inside the class
return this;
}
getBalance() {
return `${this.balance} ${this.currency}`;
}
}
const acc = new BankAccount('Alice', 100);
acc.deposit(50).deposit(25);
console.log(acc.owner); // public — ok
console.log(acc.getBalance()); // '175 USD'
// acc.balance; // Error: 'balance' is private
// acc.owner = 'Bob'; // Error: 'owner' is read-onlyWhy: extends inherits behavior; override replaces it and makes the compiler verify the parent method really exists — renaming the base method then becomes a compile error, not a silent bug.
class Logger {
log(msg: string) {
console.log(`[LOG] ${msg}`);
}
}
class TimestampLogger extends Logger {
// 'override' is checked: misspell 'log' and the compiler complains
override log(msg: string) {
super.log(`${new Date().toISOString()} ${msg}`);
}
}
// Polymorphism: a Logger variable, the child implementation runs
const logger: Logger = new TimestampLogger();
logger.log('server started');
// [LOG] 2026-06-11T09:00:00.000Z server startedWhy: an abstract class is a half-finished base — it ships shared behavior and declares abstract methods that every subclass must implement. It cannot be instantiated directly.
abstract class Shape {
abstract area(): number; // subclasses MUST implement this
describe() { // shared, already implemented
return `area = ${this.area().toFixed(2)}`;
}
}
class Circle extends Shape {
constructor(private radius: number) { super(); }
area() { return Math.PI * this.radius ** 2; }
}
class Rect extends Shape {
constructor(private w: number, private h: number) { super(); }
area() { return this.w * this.h; }
}
// new Shape(); // Error: cannot create an instance of an abstract class
const shapes: Shape[] = [new Circle(1), new Rect(2, 3)];
shapes.forEach((s) => console.log(s.describe()));
// area = 3.14
// area = 6.00