Classes and Access Modifiers

Introduction

TypeScript classes build on JavaScript’s class syntax and add typed fields, access modifiers, parameter properties, and readonly members. They are the standard way to model entities with behavior (services, models, UI components in many frameworks). This chapter covers class structure, visibility, and getters/setters.

Prerequisites

A Typed Class

Code explanation:

  • Properties are declared with types before the constructor assigns them
  • Methods annotate parameters and return types like standalone functions

Parameter Properties (Constructor Shorthand)

TypeScript can declare and assign fields in the constructor signature:

Code explanation:

  • public, private, or protected on a constructor parameter creates a class field automatically
  • readonly id cannot be reassigned after construction

Tip

Use Shorthand for Boilerplate

Parameter properties reduce repetitive this.x = x assignments. Use them when the field name matches the parameter name.

Access Modifiers

ModifierClass bodySubclassOutside
publicYesYesYes (default)
protectedYesYesNo
privateYesNoNo

Code explanation:

  • protected shares access with subclasses only
  • private is per-class, not per-instance (subclasses do not inherit private members)

Warning

Private Is Compile-Time Only

private fields still exist at runtime in modern JS. Do not rely on them for security—only for structure and tooling.

readonly Properties

typescript
class User {
  readonly id: string;
 
  constructor(id: string, public displayName: string) {
    this.id = id;
  }
}
 
const u = new User("u1", "Ada");
// u.id = "u2";  // Error
u.displayName = "Dr. Ada";

readonly allows assignment in the constructor (or at declaration) but not later reassignment.

Getters and Setters

Control access to internal state:

Code explanation:

  • get / set look like properties to callers (t.fahrenheit)
  • You can make a getter-only property by omitting the setter

implements an Interface

Classes can satisfy interface contracts:

typescript
interface Clock {
  now(): Date;
}
 
class SystemClock implements Clock {
  now(): Date {
    return new Date();
  }
}

TypeScript checks that every interface member exists with compatible types. Missing methods error at compile time.

Static Members

Belong to the class, not instances:

typescript
class Counter {
  private static instanceCount = 0;
 
  constructor(public label: string) {
    Counter.instanceCount += 1;
  }
 
  static getInstanceCount(): number {
    return Counter.instanceCount;
  }
}

Override and super

override (TypeScript 4.3+) catches typos when a parent method does not exist.

Practical Example: In-Memory Repository

Code explanation:

  • MemoryRepository is a generic class (generics chapter expands this)
  • implements Repository<T> enforces method signatures

FAQ

Do I need to declare fields if I use parameter properties?

No separate field declarations are required for parameters marked public / private / protected.

public vs no modifier?

They are the same. public is explicit; omitting the modifier defaults to public.

Can interfaces have private members?

No. private exists on classes. Interfaces only describe public shape.

Are classes required in TypeScript?

No. Many codebases use functions and plain objects. Classes fit OOP-style APIs and some frameworks.

How does this relate to JavaScript private fields #?

#field is runtime private in JS. TypeScript private is a separate compile-time feature. You can use either; avoid mixing styles without reason.

Does strict mode affect classes?

strict enables stricter checks on this, nullability, and implicit any—classes benefit like the rest of the codebase.