OOP#
TypeScript classes are JavaScript classes plus access modifiers
(public, protected, private), parameter properties,
abstract classes, implements clauses, and generic class
declarations. The runtime semantics are JavaScript’s; the
type-only features are erased at compile time.
For the runtime mechanics, see OOP.
Class declarations#
The familiar JavaScript class with type annotations on
fields, parameters, and returns.
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
distance(other: Point): number {
const dx = this.x - other.x;
const dy = this.y - other.y;
return Math.hypot(dx, dy);
}
}
const p = new Point(0, 0);
const q = new Point(3, 4);
p.distance(q); // 5
Parameter properties#
A constructor parameter annotated with public, private,
protected, or readonly is automatically declared and
assigned as a field.
class Point {
constructor(public x: number, public y: number) {}
}
const p = new Point(1, 2);
p.x; // 1
The two forms (explicit fields + assignment vs parameter properties) compile to the same JavaScript. The parameter form is shorter; the explicit form is clearer when fields need initialisation or transformation.
Access modifiers#
Modifier |
Effect |
|---|---|
|
default. Accessible from anywhere. |
|
accessible inside the class and its subclasses. |
|
compile-time only. Type-erased; nothing prevents runtime access through string keys. |
|
runtime private; cannot be accessed outside the class at all. Use this when actual privacy matters. |
class Cache {
#data = new Map<string, unknown>(); // runtime private
private hits = 0; // compile-time private
get(k: string) {
const v = this.#data.get(k);
if (v !== undefined) this.hits++;
return v;
}
}
For greenfield code, pick #name for actual
privacy and private only when interop with sibling classes
(via reflection or tests) is needed.
readonly fields#
readonly allows assignment only in the constructor.
class Config {
readonly host: string;
readonly port: number;
constructor(host: string, port: number) {
this.host = host;
this.port = port;
}
}
Inheritance#
extends for single inheritance; super(...) for the
parent constructor; super.method(...) for the parent method.
class Animal {
constructor(public name: string) {}
speak(): void { console.log(`${this.name} makes a sound`); }
}
class Dog extends Animal {
speak(): void {
super.speak();
console.log(`${this.name} barks`);
}
}
abstract#
abstract classes cannot be instantiated; abstract
methods have no body and must be implemented by subclasses.
abstract class Shape {
abstract area(): number;
describe(): string { return `area: ${this.area()}`; }
}
class Circle extends Shape {
constructor(public r: number) { super(); }
area(): number { return Math.PI * this.r ** 2; }
}
implements#
An interface describes a structure; a class can declare it
implements that interface and the compiler verifies the
class conforms.
interface Listener { onMessage(msg: string): void; }
class Logger implements Listener {
onMessage(msg: string): void { console.log(msg); }
}
Use implements to assert the contract at the
class declaration site; without it, the class still conforms
structurally but a typo silently breaks the contract.
Generics on classes#
A class can carry type parameters that thread through its methods.
class Container<T> {
constructor(public value: T) {}
map<U>(fn: (x: T) => U): Container<U> {
return new Container(fn(this.value));
}
}
const c = new Container(42); // Container<number>
const s = c.map(n => n.toString()); // Container<string>
Static members#
static puts a field or method on the class itself, not on
instances.
class Server {
static readonly DEFAULT_PORT = 8080;
static create(): Server { return new Server(); }
}
Server.DEFAULT_PORT; // 8080
Server.create(); // Server
Accessors#
get and set are runtime accessors; types describe the
read and write structures (can differ).
class Temp {
constructor(private c: number) {}
get fahrenheit(): number { return this.c * 9/5 + 32; }
set fahrenheit(f: number) { this.c = (f - 32) * 5/9; }
}
Class as a type#
A class name in a type position is the instance type. The
constructor type is typeof Class.
class Server { /* … */ }
function factory(Ctor: typeof Server): Server {
return new Ctor();
}
type ServerInstance = InstanceType<typeof Server>; // Server
this types#
Methods that return this enable fluent / builder APIs and
preserve the subclass type.
class Query {
where(cond: string): this { /* … */ return this; }
order(by: string): this { /* … */ return this; }
}
class UserQuery extends Query {
active(): this { /* … */ return this; }
}
new UserQuery().where("x").order("y").active(); // UserQuery, not Query