Classes & Constructor Parameter Properties
TypeScript extends JavaScript classes with typed members, access modifiers, and constructor parameter shorthand. The parameter property shorthand (`private name: string` in constructor) declares and initialises properties in one step — a major reduction in boilerplate.
Classes — Typed Properties & Constructor Shorthand
// ── Basic typed class ────────────────────────────────────────
class Task {
id: number;
title: string;
status: TaskStatus;
createdAt: Date;
constructor(id: number, title: string) {
this.id = id;
this.title = title;
this.status = "todo";
this.createdAt = new Date();
}
}
// ── Constructor parameter properties (shorthand) ───────────────
// Combining declaration + initialisation in one place:
class User {
createdAt = new Date(); // class field with default
updatedAt = new Date();
constructor(
public readonly id: number, // public + readonly: visible, immutable
public name: string, // public: readable/writable from outside
private email: string, // private: class-internal only
protected role: "member" | "admin" = "member", // protected + default
) {}
getEmail(): string {
return this.email; // ✅ accessible internally
}
isAdmin(): boolean {
return this.role === "admin";
}
}
const user = new User(1, "Alice", "alice@example.com");
console.log(user.name); // ✅ public
console.log(user.id); // ✅ public readonly
// console.log(user.email); // ❌ Error: private
user.name = "Alicia"; // ✅ public mutable
// user.id = 2; // ❌ Error: readonly
// ── Static members ────────────────────────────────────────────
class TaskSequence {
private static nextId = 1; // shared across all instances
public static readonly MAX = 1000; // public constant
static generate(): number {
return TaskSequence.nextId++;
}
}
const id1 = TaskSequence.generate(); // 1
const id2 = TaskSequence.generate(); // 2
// ── Getter & Setter ───────────────────────────────────────────
class TimedTask {
private _dueDate: Date | null = null;
get dueDate(): Date | null { return this._dueDate; }
set dueDate(value: Date | null) {
if (value !== null && value < new Date()) {
throw new RangeError("Due date cannot be in the past");
}
this._dueDate = value;
this.updatedAt = new Date();
}
constructor(
public readonly id: number,
public title: string,
public updatedAt = new Date(),
) {}
}Common Mistakes
- Forgetting to initialise class properties — TypeScript with `strictPropertyInitialization: true` (part of `strict`) requires all properties to be initialised in the constructor or with a default value. Use the `!` postfix only when you know it'll be initialised before use.
- Using `private` for truly encapsulated data in runtime — TypeScript's `private` is compile-time only. At runtime, it's a plain JS property. For true runtime privacy, use JS private fields (`#field`).
- Overusing static members — statics on a class are equivalent to module-level variables. Prefer module exports over static properties for data that doesn't vary per instance.
Tip
Tip
Practice Classes Constructor Parameter Properties in small, isolated examples before integrating into larger projects. Breaking concepts into small experiments builds genuine understanding faster than reading alone.
Classes are syntactic sugar over prototypes.
Practice Task
Note
Practice Task — (1) Write a working example of Classes Constructor Parameter Properties from scratch without looking at notes. (2) Modify it to handle an edge case (empty input, null value, or error state). (3) Share your solution in the Priygop community for feedback.
Quick Quiz
Common Mistake
Warning
A common mistake with Classes Constructor Parameter Properties is skipping edge case testing — empty inputs, null values, and unexpected data types. Always validate boundary conditions to write robust, production-ready typescript code.
Key Takeaways
- TypeScript extends JavaScript classes with typed members, access modifiers, and constructor parameter shorthand.
- Forgetting to initialise class properties — TypeScript with `strictPropertyInitialization: true` (part of `strict`) requires all properties to be initialised in the constructor or with a default value. Use the `!` postfix only when you know it'll be initialised before use.
- Using `private` for truly encapsulated data in runtime — TypeScript's `private` is compile-time only. At runtime, it's a plain JS property. For true runtime privacy, use JS private fields (`#field`).
- Overusing static members — statics on a class are equivalent to module-level variables. Prefer module exports over static properties for data that doesn't vary per instance.