Lab 04: Classes & OOP

Objective

Build TypeScript classes with access modifiers, abstract classes, readonly, static members, parameter properties, and proper OOP patterns.

Background

TypeScript classes extend JavaScript's ES2015 classes with type annotations and access modifiers (private, protected, public). TypeScript's private is checked at compile time; JavaScript's #private (also supported) is enforced at runtime. TypeScript classes compile to regular JavaScript constructor functions.

Time

35 minutes

Prerequisites

  • Lab 01–03

Tools

  • Docker image: zchencow/innozverse-ts:latest


Lab Instructions

Step 1: Class Basics & Parameter Properties

💡 Parameter properties (private readonly accountId: string) declare AND assign properties in the constructor — no need to write this.accountId = accountId manually. This is a TypeScript-only feature that reduces boilerplate significantly, especially for DTOs and value objects.

📸 Verified Output:


Step 2: Inheritance & Protected Members

💡 protected members are accessible within the class AND its subclasses, but not from outside. Use protected for properties/methods that subclasses need to override behavior. private means truly internal — even subclasses can't access it. TypeScript's access modifiers are compile-time only (unlike #private).

📸 Verified Output:


Step 3: Static Members & Factory Methods

💡 Private constructor + static factory methods is the Named Constructor pattern — Color.fromHex() is clearer than new Color() with hex parsing inside. It also prevents subclassing (you can't call super() if the constructor is private to the parent). Use it for value objects and singletons.

📸 Verified Output:


Step 4: Interfaces + implements

💡 implements vs extends: extends inherits code from a parent class; implements only checks that your class has the required shape — no code is inherited. A class can implement multiple interfaces but only extend one class. Think of interfaces as contracts and classes as implementations.

📸 Verified Output:


Step 5: Mixins

💡 Mixins add capabilities without inheritance hierarchies. Timestamped(User) wraps User in a new anonymous class that adds timestamp properties. Combining Timestamped, Activatable, and Serializable gives you a class with all three features. This is how Angular's @Injectable() decorator works internally.

📸 Verified Output:


Step 6: Generic Classes

💡 Generic classes carry the type parameter through all methods. Stack<number> creates a stack where push only accepts numbers and pop returns number | undefined. The type is resolved at instantiation — one class definition, infinite type-safe variants.

📸 Verified Output:


Step 7: Abstract Classes & Template Method

📸 Verified Output:


Step 8: Complete — Entity Framework Pattern

💡 BaseEntity.nextId++ is a class-level counter — static properties are shared across all instances. Each subclass that calls super() gets a unique ID. In production, IDs come from databases; in tests, this auto-increment pattern avoids external dependencies.

📸 Verified Output:


Summary

TypeScript OOP is powerful and expressive. You've covered parameter properties, inheritance, abstract classes, implements, static members, mixins, generic classes, the Template Method pattern, and an entity framework. These patterns power Angular, NestJS, TypeORM, and every TypeScript-first backend.

Further Reading

Last updated