Mastering TypeScript Class Types and Member Modifiers

TypeScript provides powerful advanced type mechanisms that extend JavaScript's capabilities. While the language offers sophisticated features like intersection types, generics with keyof operators, index signatures, and mapped types, classes remain fundamental to building robust type-safe applications. Understanding how TypeScript enhances classes with type annotations and member modifiers is essential for leveraging the full power of the type system.

Classes as Types

In TypeScript, a class declaration serves a dual purpose: it creates a runtime construct and simultaneously defines a type that represents instances of that class. The type inference engine automatically recognizes the type relationship between a class and its instances.

class Account {}

const userAccount = new Account()
// userAccount has the type Account

Property Initialization

Class properties can be declared with explicit type annotations or initialized with default values. When a default value is provided, TypeScript's type inference determnies the appropriate type automatically.

class UserProfile {
    username: string      // Type annotation without initial value
    status = 'active'     // Type inferred as string
}

Constructor Functions

The constructor method initializes instance properties and must have typed parameters. Unlike regular functions, constructors don't require return type annotations as they always return the class instance.

class Vehicle {
    wheels: number
    brand: string
    
    constructor(wheelCount: number, manufacturer: string) {
        this.wheels = wheelCount
        this.brand = manufacturer
    }
}

Instance Methods

Methods within classes follow the same type annotation patterns as standalone functions, allowing precise specification of parameter and return types.

class Rectangle {
    width = 100
    height = 50
    
    resize(factor: number): void {
        this.width *= factor
        this.height *= factor
    }
}

Inheritance Patterns

TypeScript supports two primary inheritance mechanisms: extending base classes and implementing interfaces. The extends keyword creates classical prototype-based inheritance, while implements enforces contract compliance with interface definitions.

// Extending a base class
class Device {
    powerOn() {
        console.log('Device starting...')
    }
}

class Smartphone extends Device {
    ring() {
        console.log('Beep beep!')
    }
}

const phone = new Smartphone()
phone.powerOn()  // Inherited method
phone.ring()     // Own method
// Implementing an interface
interface Drawable {
    draw(): void
}

class Circle implements Drawable {
    draw() {
        console.log('Rendering circle...')
    }
}

Member Visibility Modifiers

TypeScript introduces three visibility modifiers to control access to class members: public, protected, and private. These modifiers provide encapsulation at the type-checking level.

The public modifier, which is the default, makes members accessible from anywhere:

class Vehicle {
    public drive() {
        console.log('Driving forward!')
    }
}

The protected modifier restricts access to the declaring class and its subclasses, but not to instance objects:

class Machine {
    protected operate() {
        console.log('Machine operating...')
    }
}

class Robot extends Machine {
    execute() {
        console.log('Robot executing...')
        this.operate()  // Accessible within subclass
    }
}

// const bot = new Robot()
// bot.operate()  // Error: Property is protected

The private modifier confines visibility to the containing class only:

class Aircraft {
    protected fly() {
        console.log('Flying...')
    }
}

class Drone extends Aircraft {
    private calibrate() {
        console.log('Calibrating sensors...')
    }
    
    startFlight() {
        this.fly()        // Accessible (protected from parent)
        this.calibrate()  // Accessible (private to Drone)
    }
}

// const drone = new Drone()
// drone.calibrate()  // Error: Property is private

Readon Properties

The readonly modifier prevents property modification after initialization, typically within the constructor. This ensures immutability for critical configuration values.

class Configuration {
    readonly maxConnections: number = 5
    
    constructor(limit: number) {
        this.maxConnections = limit  // Allowed in constructor
    }
}

// const config = new Configuration(10)
// config.maxConnections = 20  // Error: Cannot assign to readonly

Interfaces can also specify readonly properties, enforcing immutability on object literals:

interface DatabaseConfig {
    readonly host: string
}

let db: DatabaseConfig = {
    host: 'localhost'
}

// db.host = 'remote'  // Error: Cannot assign to readonly

Tags: TypeScript Classes visibility-modifiers readonly Inheritance

Posted on Thu, 10 Sep 2026 16:51:40 +0000 by CBI Web