← thecodex.expert · The Codex Family of Knowledge
TypeScript

Classes in TypeScript

TypeScript’s private keyword is a compile-time-only restriction — the compiled JavaScript has no real privacy at all, unlike native JavaScript’s # private fields.

TypeScript 6.0 private is compile-time only Last verified:
Where this bites you

A method only knows its object through this, and this is decided by how the method is called, not where it was defined. Pass counter.increment somewhere as a plain function (an event handler, a setTimeout callback, an array map) and it is called with no object at all. Class bodies run in strict mode, so this is undefined and the method crashes. TypeScript compiles it without a word.

TypeScriptthis_bug.ts
class Counter {
    count = 0;

    increment() {
        this.count++;
        console.log("count is", this.count);
    }
}

const counter = new Counter();
counter.increment();                 // count is 1

const onClick = counter.increment;   // detached from the instance
onClick();
// TypeError: Cannot read properties of undefined (reading 'count')
Canonical Definition

TypeScript classes add access modifiers on top of JavaScript's class syntax: public (the default, accessible anywhere), private (only within the declaring class), and protected (the declaring class and its subclasses). readonly prevents reassignment after construction. implements checks that a class satisfies an interface's shape at compile time. All of these are TypeScript-only checks — they're stripped away entirely when compiled to JavaScript, so private in particular offers no real runtime protection, unlike JavaScript's native #-prefixed private fields.

Access modifiers: public, private, protected

public is the default and rarely written explicitly; private and protected are checked only by the TypeScript compiler, not enforced by the JavaScript runtime that actually executes.

TypeScriptaccess_modifiers.ts
class BankAccount {
    public owner: string;
    private balance: number;

    constructor(owner: string, balance: number) {
        this.owner = owner;
        this.balance = balance;
    }

    public deposit(amount: number) {
        this.balance += amount;
    }
}

const acc = new BankAccount("Alice", 100);
acc.deposit(50);        // fine — deposit is public
// acc.balance;          // COMPILE ERROR: balance is private

readonly properties

readonly blocks reassignment after the constructor runs, but only at the TypeScript-checking layer — it's a compile-time guarantee, not a runtime freeze like Object.freeze.

TypeScriptreadonly_props.ts
class Point {
    readonly x: number;
    readonly y: number;

    constructor(x: number, y: number) {
        this.x = x;   // fine — inside the constructor
        this.y = y;
    }
}

const p = new Point(3, 4);
// p.x = 10;   // COMPILE ERROR: x is readonly

implements: enforcing an interface's shape

implements is purely a compile-time check that the class satisfies the interface — it doesn't affect runtime behavior at all, and a class can implement multiple interfaces at once.

TypeScriptimplements_keyword.ts
interface Flyable {
    fly(): void;
}

class Bird implements Flyable {
    fly() {
        console.log("Flying!");
    }
}
// class Rock implements Flyable {}   // COMPILE ERROR: missing fly() method

Access modifiers, readonly and implements are all checked at compile time, but this binding is pure JavaScript runtime behaviour, so none of them help here. The usual fix for a method that will be handed around as a callback is to define it as an arrow-function property: an arrow function captures this from the instance when the object is constructed (.bind(this) in the constructor does the same):

TypeScriptthis_fix.ts
class Counter {
    count = 0;

    increment = () => {
        this.count++;
        console.log("count is", this.count);
    };
}

const counter = new Counter();
counter.increment();                 // count is 1

const onClick = counter.increment;   // arrow property keeps `this`
onClick();                           // count is 2

Sources

1
Microsoft. TypeScript Handbook, "Classes", typescriptlang.org/docs/handbook/2/classes.html.