TypeScript adds type annotations, access modifiers, and parameter properties to JavaScript classes. Classes define blueprints for objects — they bundle data (properties) and behaviour (methods) together.
Basic Class
TypeScript
class Student {
name: string;
grade: number;
constructor(name: string, grade: number) {
this.name = name;
this.grade = grade;
}
isPassing(): boolean {
return this.grade >= 40;
}
toString(): string {
return `${this.name} (${this.grade})`;
}
}
const ram = new Student("Ram", 85);
console.log(ram.isPassing()); // true
console.log(ram.toString()); // "Ram (85)"Parameter Properties (Shorthand)
TypeScript can declare and assign properties in one step by adding an access modifier to the constructor parameter:
TypeScript
// Longhand
class Student {
name: string;
grade: number;
constructor(name: string, grade: number) {
this.name = name;
this.grade = grade;
}
}
// Shorthand — identical result
class Student {
constructor(
public name: string,
public grade: number,
private _id: string,
) {}
}| Modifier | Class | Subclass | Outside |
|---|---|---|---|
public |
✅ | ✅ | ✅ |
protected |
✅ | ✅ | ❌ |
private |
✅ | ❌ | ❌ |
readonly |
✅ (cannot modify) | ✅ | ✅ |
Methods
TypeScript
class Calculator {
private result: number = 0;
add(n: number): this {
this.result += n;
return this; // enables chaining
}
multiply(n: number): this {
this.result *= n;
return this;
}
getValue(): number {
return this.result;
}
}
const calc = new Calculator();
const value = calc.add(5).multiply(3).getValue(); // 15Inheritance
TypeScript
class Animal {
constructor(public name: string) {}
speak(): string {
return `${this.name} makes a sound`;
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name); // call parent constructor
}
override speak(): string {
return `${this.name} barks`;
}
}
const rex = new Dog("Rex", "Labrador");
console.log(rex.speak()); // "Rex barks"Use the override keyword (TypeScript 4.3+) when overriding a parent
method — it prevents typos and ensures the parent actually has that
method.
Abstract Classes
Abstract classes cannot be instantiated directly — they are base classes that other classes extend:
TypeScript
abstract class Shape {
abstract area(): number; // subclasses MUST implement this
describe(): string {
return `Area: ${this.area().toFixed(2)}`;
}
}
class Circle extends Shape {
constructor(public radius: number) {
super();
}
area(): number {
return Math.PI * this.radius ** 2;
}
}
class Rectangle extends Shape {
constructor(public width: number, public height: number) {
super();
}
area(): number {
return this.width * this.height;
}
}
// const s = new Shape(); // Error: Cannot instantiate abstract class
const c = new Circle(5);
console.log(c.describe()); // "Area: 78.54"Getters and Setters
TypeScript
class Temperature {
private _celsius: number;
constructor(celsius: number) {
this._celsius = celsius;
}
get fahrenheit(): number {
return this._celsius * 9 / 5 + 32;
}
set celsius(value: number) {
if (value < -273.15) throw new Error("Below absolute zero");
this._celsius = value;
}
}
const t = new Temperature(100);
console.log(t.fahrenheit); // 212
t.celsius = 0;
console.log(t.fahrenheit); // 32Tips
- Use parameter properties — they eliminate boilerplate.
- Favour composition over inheritance —
has-ais often better thanis-a. - Use abstract classes when you need shared implementation across subclasses.
- Keep classes small — one class, one responsibility.
Next: generics — write code that works with any type.