Reading — step 1 of 6
Learn
TypeScript adds access modifiers and other class features on top of JavaScript classes — making OOP-style code work the way you expect.
Access modifiers
class BankAccount {
public owner: string;
private balance: number;
protected accountNumber: string;
readonly createdAt: Date;
constructor(owner: string, accountNumber: string) {
this.owner = owner;
this.accountNumber = accountNumber;
this.balance = 0;
this.createdAt = new Date();
}
deposit(amount: number): void {
if (amount > 0) this.balance += amount;
}
getBalance(): number {
return this.balance;
}
}
public(default) — accessible everywhere.private— only within this class.protected— within this class and subclasses.readonly— can be set in the constructor but not reassigned later.
At RUNTIME, only #name (real private) gives true encapsulation. private is enforced at compile time only — the JS output is just a normal property.
Parameter properties — shortcut
Declare and assign in one line:
class Point {
constructor(
public readonly x: number,
public readonly y: number,
) {}
}
const p = new Point(3, 4);
console.log(p.x); // 3
The public readonly in the constructor parameter both declares the field AND assigns it. Saves the boilerplate of this.x = x; this.y = y;.
Inheritance and super
class Animal {
constructor(public name: string) {}
describe(): string {
return `${this.name} is an animal`;
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name);
}
describe(): string {
return `${this.name} is a ${this.breed}`;
}
parentDescribe(): string {
return super.describe(); // call parent's version
}
}
Abstract classes
Classes that can't be instantiated directly — used as base templates:
abstract class Shape {
abstract area(): number;
describe(): string {
return `area: ${this.area()}`;
}
}
class Circle extends Shape {
constructor(private radius: number) { super(); }
area(): number { return Math.PI * this.radius ** 2; }
}
// const s = new Shape(); // ✗ compile error
const c = new Circle(5);
console.log(c.describe());
abstract methods have no body — subclasses must implement them.
Implementing interfaces
interface Greetable {
greet(): string;
}
class User implements Greetable {
constructor(private name: string) {}
greet(): string { return `Hi, ${this.name}`; }
}
implements enforces the shape at compile time. Multiple interfaces are allowed: class X implements A, B, C.
Static members
Attached to the class, not instances:
class IDGenerator {
private static nextId = 0;
static getId(): number {
return ++IDGenerator.nextId;
}
}
IDGenerator.getId(); // 1
IDGenerator.getId(); // 2
Common mistakes
- Confusing
privatewith#private—#nameis real private (enforced at runtime);private nameis compile-time only. - Forgetting
super()in subclass constructor — required before usingthis. - Using
readonlyfor deep immutability — only locks the property reference, not the object's contents.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…