Classes
A class defines a custom type with fields (data) and methods (behavior). This page covers defining and using classes; the rest of this section goes deeper: Encapsulation & Accessors for access control, Static Members for class-level state, and Inheritance for subclassing.
Defining a class
Declare fields with a type, then create instances with new:
class Rectangle { public width: f64; public height: f64;}
let rect: Rectangle = new Rectangle();rect.width = 10.0;rect.height = 5.0;Constructors
A constructor initializes an object’s fields. It runs automatically when you write
new ClassName(...):
class Point { public x: i32; public y: i32;
constructor(x: i32, y: i32) { this.x = x; this.y = y; }}
function main(): i32 { let p: Point = new Point(10, 20); return p.x + p.y; // => 30}Methods
Methods are functions attached to a class that operate on the instance:
class Rectangle { public width: f64; public height: f64;
constructor(w: f64, h: f64) { this.width = w; this.height = h; }
public area(): f64 { return this.width * this.height; }
public perimeter(): f64 { return 2.0 * (this.width + this.height); }}
let rect: Rectangle = new Rectangle(10.0, 5.0);let a: f64 = rect.area(); // 50.0let p: f64 = rect.perimeter(); // 30.0Methods can take rest parameters — prefix the final
parameter with ...:
class Accumulator { public base: i32;
constructor(base: i32) { this.base = base; }
public sum(...nums: i32[]): i32 { let total: i32 = this.base; for (let i: i32 = 0; i < nums.length; i++) { total += nums[i]; } return total; }}
let acc: Accumulator = new Accumulator(10);let total: i32 = acc.sum(1, 2, 3); // 16The this keyword
Inside a method, this refers to the current instance — use it to read and update the object’s own
fields:
class Counter { public value: i32;
constructor(start: i32) { this.value = start; }
public increment(): void { this.value = this.value + 1; }
public getValue(): i32 { return this.value; }}
function main(): i32 { let c: Counter = new Counter(41); c.increment(); return c.getValue(); // => 42}Object references
Objects are passed by reference. A function that mutates its parameter changes the caller’s object:
class Box { public value: i32; constructor(v: i32) { this.value = v; }}
function modifyBox(box: Box): void { box.value = 999;}
function main(): i32 { let myBox: Box = new Box(10); modifyBox(myBox); return myBox.value; // => 999}Nested objects
A field can hold another object, letting you compose larger structures:
class Point { public x: i32; public y: i32; constructor(x: i32, y: i32) { this.x = x; this.y = y; }}
class Line { public start: Point; public end: Point;
constructor(p1: Point, p2: Point) { this.start = p1; this.end = p2; }
public length(): i32 { let dx: i32 = this.end.x - this.start.x; let dy: i32 = this.end.y - this.start.y; return dx + dy; // Manhattan distance }}
function main(): i32 { let line: Line = new Line(new Point(0, 0), new Point(10, 20)); return line.length(); // => 30}Null and null-safety
An object variable can be null, either explicitly or when left uninitialized:
class Node { public value: i32; public next: Node;
constructor(v: i32) { this.value = v; this.next = null; // no next node yet }}Zeus checks for null on every property access. Reaching through a null reference throws a
NullReferenceException:
let person: Person; // null by defaultconsole.log(person.name); // throws NullReferenceExceptionfunction getName(person: Person): string { try { return person.name; } catch (e: Error) { return "Unknown"; }}Classes with arrays
A field can be an array. Initialize it in the constructor, then use the array methods:
class Team { public scores: i32[];
constructor() { this.scores = new i32[]; }
public addScore(score: i32): void { this.scores.push(score); }
public getScore(index: i32): i32 { return this.scores.get(index); }}
function main(): i32 { let team: Team = new Team(); team.addScore(10); team.addScore(20); team.addScore(30); return team.getScore(1); // => 20}Anonymous classes
A class expression creates a type inline, without a top-level declaration — handy for one-off objects.
Assign it to a const and use that name as the type:
function main(): i32 { const Counter = class { public n: i32; constructor(start: i32) { this.n = start; }
inc(): i32 { this.n = this.n + 1; return this.n; } }
let c = new Counter(9); return c.inc(); // => 10}You can also give the expression an internal name — both the variable and the class name are then usable:
function main(): i32 { const Vec = class Vector { public x: i32; public y: i32; constructor(x: i32, y: i32) { this.x = x; this.y = y; } sum(): i32 { return this.x + this.y; } }
let a = new Vec(3, 4); // via the const let b = new Vector(1, 2); // via the class name return a.sum() + b.sum(); // => 10}Or define and instantiate in a single expression — the class equivalent of an IIFE:
function main(): i32 { let obj = new (class { public v: i32; constructor(v: i32) { this.v = v; } get(): i32 { return this.v; } })(42);
return obj.get(); // => 42}