TypeScript Classes

TypeScript classes are JavaScript classes with type annotations and extra features: access modifiers, readonly properties, parameter properties and abstract classes.

Typed Properties and Constructors

Properties must be declared with their types. With strict mode, each one must be initialized in the constructor or with a default.

class Product {
  name: string;
  price: number;
  constructor(name: string, price: number) {
    this.name = name;
    this.price = price;
  }
  discounted(percent: number): number {
    return this.price * (1 - percent / 100);
  }
}
const p = new Product("Almonds", 15);
console.log(p.discounted(20));
12

Access Modifiers

  • public (default): accessible everywhere
  • private: only inside the class (checked at compile time only)
  • protected: inside the class and its subclasses
  • #field: JavaScript private field, enforced at runtime too

Parameter Properties and readonly

Adding a modifier to a constructor parameter declares and assigns the property in one step, removing boilerplate.

class BankAccount {
  constructor(
    public readonly owner: string,
    private balance: number = 0,
  ) {}

  deposit(amount: number) {
    this.balance += amount;
    return this;
  }
  get summary() {
    return `${this.owner}: ${this.balance}`;
  }
}
const acc = new BankAccount("Usman").deposit(500).deposit(250);
console.log(acc.summary);
// acc.balance = 1e6;   // Error: Property 'balance' is private.
// acc.owner = "Other"; // Error: Cannot assign to 'owner' because it is a read-only property.
Usman: 750

Inheritance and protected

The override keyword marks a method that replaces a parent method; with noImplicitOverride the compiler requires it.

class Employee {
  constructor(public name: string, protected salary: number) {}
  describe() {
    return `${this.name} earns ${this.salary}`;
  }
}
class Manager extends Employee {
  constructor(name: string, salary: number, private bonus: number) {
    super(name, salary);
  }
  override describe() {
    return `${super.describe()} + ${this.bonus} bonus`;
  }
}
console.log(new Manager("Emma", 5000, 800).describe());
Emma earns 5000 + 800 bonus

Abstract Classes

An abstract class cannot be instantiated. It provides shared code and declares abstract methods that subclasses must implement.

abstract class Notifier {
  abstract send(msg: string): string;
  notify(msg: string) {
    return "[" + new Date(0).getUTCFullYear() + "] " + this.send(msg);
  }
}
class EmailNotifier extends Notifier {
  send(msg: string) {
    return "Email: " + msg;
  }
}
// new Notifier(); // Error: Cannot create an instance of an abstract class.
console.log(new EmailNotifier().notify("Order shipped"));
[1970] Email: Order shipped

Frequently asked questions

What is the difference between private and # in TypeScript?

private is checked only by the compiler and disappears in JavaScript. #fields are real JavaScript private fields, enforced at runtime.

What are parameter properties in TypeScript?

Constructor parameters with a modifier like public, private or readonly. TypeScript turns them into class properties automatically.

When should I use an abstract class instead of an interface?

Use an abstract class when subclasses should share real code. Use an interface when you only need to describe a shape with no implementation.