Part 1: Classes and Objects - Building Blocks

Introduction

I wrote procedural TypeScript code for my first year—functions that manipulated plain objects, validation scattered across files, business logic mixed with data access. Then I built a user authentication service that needed to handle multiple auth providers (email, OAuth, SAML). The procedural approach became unmanageable.

Classes changed everything. A User class encapsulated all user-related behavior. An AuthProvider class hierarchy handled different authentication methods. Code became organized, testable, and maintainable. This article shows you how to think in objects and build production-ready TypeScript classes.

From Functions to Classes

The Procedural Way

// user-functions.ts
interface UserData {
    id: string;
    email: string;
    passwordHash: string;
    createdAt: Date;
}

function createUser(email: string, password: string): UserData {
    return {
        id: generateId(),
        email: email.toLowerCase().trim(),
        passwordHash: hashPassword(password),
        createdAt: new Date()
    };
}

function validatePassword(user: UserData, password: string): boolean {
    return compareHash(password, user.passwordHash);
}

function isEmailVerified(user: UserData): boolean {
    // Where do we store verification status?
    // Scattered logic!
    return false;
}

Problems:

  • Functions and data are separate

  • Validation logic scattered

  • No clear ownership of behavior

  • Hard to extend (what about OAuth users?)

The OOP Way

Benefits:

  • Data and behavior together

  • Clear ownership

  • Encapsulation (private methods)

  • Easy to extend

Class Basics

Defining a Class

Creating Instances (Objects)

TypeScript Shorthand: Parameter Properties

TypeScript offers a concise syntax for constructor parameters:

Much cleaner! I use this in all my TypeScript classes.

Real Example: Order Management System

I built an e-commerce order system. Here's how classes organized the domain logic:

Using the Order Classes

Why classes here?

  • Order and OrderItem encapsulate business rules

  • Status transitions controlled by methods

  • Invalid operations prevented

  • Easy to test each class independently

Static Members

Static members belong to the class itself, not instances:

Real Use Case: Configuration

Readonly Properties

Prevent property modification after construction:

Methods vs Functions

Instance Methods

Access instance data via this:

Arrow Functions in Classes

Arrow functions have different this binding:

I use arrow functions for event handlers and callbacks.

Real Example: API Client

Class Relationships: Has-A

Classes can contain other classes:

Common Patterns

Factory Method

Builder Pattern

Best Practices

1. Single Responsibility

Each class should have one reason to change:

2. Immutability When Possible

3. Meaningful Names

What's Next

You now know:

  • Defining classes with properties and methods

  • Creating instances with constructors

  • TypeScript parameter properties shorthand

  • Static vs instance members

  • Readonly properties

  • Class composition (has-a relationships)

In Part 2: Encapsulation and Access Modifiers, you'll learn how to protect data with private/public/protected modifiers, create getters/setters, and understand information hiding principles.


Based on building TypeScript backend services, domain models, and API clients for production systems.

Last updated