TypeScript Classes

Welcome to The Coding College, where we make programming concepts easy to understand! At The Coding College, we are passionate about helping you improve your coding skills. In this post, we’ll explore TypeScript Classes, a key feature of object-oriented programming (OOP) in TypeScript.

What Are Classes in TypeScript?

A class in TypeScript is a blueprint for creating objects with shared properties and methods. It simplifies OOP concepts by introducing structure and type safety into JavaScript’s class system.

Why Use Classes in TypeScript?

  1. Encapsulation: Classes bundle data and behavior together.
  2. Reusability: Define reusable blueprints for objects.
  3. Inheritance: Extend functionality from one class to another.
  4. Type Safety: TypeScript adds static types to class properties and methods.

Declaring a Class

Basic Syntax

class ClassName {
    propertyName: PropertyType;

    constructor(parameterName: ParameterType) {
        this.propertyName = parameterName;
    }

    methodName(): ReturnType {
        // Method body
    }
}

Example: A Simple Class

class Person {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    greet(): string {
        return `Hello, my name is ${this.name}`;
    }
}

const person = new Person("Alice");
console.log(person.greet()); // Output: Hello, my name is Alice

Access Modifiers

TypeScript classes support access modifiers to control the visibility of properties and methods:

  1. public (default): Accessible anywhere.
  2. private: Accessible only within the class.
  3. protected: Accessible within the class and subclasses.

Example: Using Access Modifiers

class Employee {
    public name: string;
    private salary: number;

    constructor(name: string, salary: number) {
        this.name = name;
        this.salary = salary;
    }

    getSalary(): number {
        return this.salary;
    }
}

const employee = new Employee("Bob", 50000);
console.log(employee.name); // Output: Bob
// console.log(employee.salary); // Error: Property 'salary' is private
console.log(employee.getSalary()); // Output: 50000

Read-Only Properties

Properties can be marked as readonly, making them immutable after initialization.

class Car {
    readonly brand: string;

    constructor(brand: string) {
        this.brand = brand;
    }
}

const car = new Car("Toyota");
console.log(car.brand); // Output: Toyota
// car.brand = "Honda"; // Error: Cannot assign to 'brand' because it is a read-only property

Getters and Setters

Use getters and setters to control access to class properties.

Example: Getters and Setters

class Circle {
    private _radius: number;

    constructor(radius: number) {
        this._radius = radius;
    }

    get radius(): number {
        return this._radius;
    }

    set radius(value: number) {
        if (value > 0) {
            this._radius = value;
        } else {
            throw new Error("Radius must be positive");
        }
    }
}

const circle = new Circle(5);
console.log(circle.radius); // Output: 5
circle.radius = 10;
console.log(circle.radius); // Output: 10

Inheritance

Classes can extend other classes to reuse and enhance functionality.

Example: Inheritance

class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    move(): string {
        return `${this.name} is moving`;
    }
}

class Dog extends Animal {
    bark(): string {
        return `${this.name} says Woof!`;
    }
}

const dog = new Dog("Buddy");
console.log(dog.move()); // Output: Buddy is moving
console.log(dog.bark()); // Output: Buddy says Woof!

Abstract Classes

An abstract class cannot be instantiated and serves as a base for other classes.

Example: Abstract Class

abstract class Shape {
    abstract area(): number;

    describe(): string {
        return "This is a shape";
    }
}

class Rectangle extends Shape {
    width: number;
    height: number;

    constructor(width: number, height: number) {
        super();
        this.width = width;
        this.height = height;
    }

    area(): number {
        return this.width * this.height;
    }
}

const rectangle = new Rectangle(10, 5);
console.log(rectangle.area()); // Output: 50

Static Properties and Methods

Static members belong to the class itself, not individual instances.

Example: Static Members

class MathUtils {
    static pi: number = 3.14159;

    static calculateCircumference(radius: number): number {
        return 2 * MathUtils.pi * radius;
    }
}

console.log(MathUtils.pi); // Output: 3.14159
console.log(MathUtils.calculateCircumference(5)); // Output: 31.4159

Implementing Interfaces

Classes can implement interfaces to enforce specific structures.

Example: Class Implementing an Interface

interface Printable {
    print(): void;
}

class Document implements Printable {
    content: string;

    constructor(content: string) {
        this.content = content;
    }

    print(): void {
        console.log(this.content);
    }
}

const doc = new Document("TypeScript Classes are powerful!");
doc.print(); // Output: TypeScript Classes are powerful!

Real-World Applications

  1. Reusable Components: Use classes to create reusable UI components in frameworks like Angular.
  2. Data Models: Define structured models for API data.
  3. Encapsulation: Hide implementation details and expose only what’s necessary.

Best Practices

  1. Encapsulate Logic: Use private and protected to enforce encapsulation.
  2. Prefer Read-Only for Constants: Mark properties that shouldn’t change as readonly.
  3. Keep Classes Small: Follow the Single Responsibility Principle (SRP).
  4. Use Abstract Classes for Base Behavior: Define common functionality in abstract classes.
  5. Document Classes and Methods: Write clear comments for better maintainability.

Common Pitfalls

  1. Overuse of Static Methods: Overusing static members can make code harder to test.
  2. Ignoring Access Modifiers: Always define access modifiers for clarity.
  3. Complex Inheritance Chains: Deep inheritance hierarchies can lead to rigid and error-prone designs.

Conclusion

Classes in TypeScript offer a robust way to structure and organize your code. With features like inheritance, encapsulation, and static typing, they enhance your ability to build scalable, maintainable applications.

Leave a Comment