7. Classes

Classes are a fundamental concept in object-oriented programming (OOP) and TypeScript. They enable you to create reusable, structured code by defining blueprints for objects. In this article, we’ll explore how to define classes in TypeScript, use constructors, and work with properties.

Defining Classes

In TypeScript, you can define classes using the class keyword. A class encapsulates data (in the form of properties) and behavior (in the form of methods) into a single unit. Here’s an example of defining a simple class:

class Car {
    // Properties
    make: string;
    model: string;
    year: number;

    // Constructor
    constructor(make: string, model: string, year: number) {
        this.make = make;
        this.model = model;
        this.year = year;
    }

    // Method
    startEngine() {
        console.log(`${this.make} ${this.model}'s engine started.`);
    }
}

In the Car class, we have properties (make, model, year), a constructor that initializes these properties, and a method (startEngine) to perform an action.

Constructors and Properties

Constructors

A constructor is a special method in a class that is automatically called when you create a new instance (object) of the class. It is used to initialize the object’s properties.

const myCar = new Car("Toyota", "Camry", 2022);

In this example, we create a new instance of the Car class by calling the constructor with specific arguments. The constructor sets the make, model, and year properties of myCar.

Properties

Properties are variables that belong to a class and represent the object’s state. They can be accessed and modified within the class methods.

console.log(myCar.make); // "Toyota"
console.log(myCar.model); // "Camry"
console.log(myCar.year);  // 2022

myCar.startEngine(); // Output: "Toyota Camry's engine started."

In this code, we access the make, model, and year properties of myCar and call the startEngine method.

Access Modifiers

Access modifiers (such as public, private, and protected) control the visibility and accessibility of class members (properties and methods). By default, class members are public, which means they can be accessed from outside the class.

class Person {
    private age: number; // private property

    constructor(age: number) {
        this.age = age;
    }

    getAge(): number {
        return this.age;
    }
}

const person = new Person(30);

// Accessing a private property directly would result in an error
console.log(person.age); // Error: Property 'age' is private and only accessible within class 'Person'.

// Accessing the age using the getAge method
console.log(person.getAge()); // 30

In this example, the age property is marked as private, making it inaccessible from outside the Person class. We provide a public method getAge to access the age property’s value.

Methods and Access Modifiers

Methods

Methods are functions defined within a class, enabling objects of that class to perform specific actions or behaviors. Methods encapsulate behavior that can be applied to instances of a class.

class Calculator {
    add(a: number, b: number): number {
        return a + b;
    }
}

const calc = new Calculator();
console.log(calc.add(2, 3)); // 5

In this example, the add method of the Calculator class performs addition.

Access Modifiers

Access modifiers control the visibility and accessibility of class members (properties and methods). TypeScript supports three main access modifiers: public, private, and protected.

  • public: Members are accessible from any code.
  • private: Members are only accessible within the class.
  • protected: Members are accessible within the class and its subclasses.
class Person {
    private age: number;

    constructor(age: number) {
        this.age = age;
    }

    getAge(): number {
        return this.age;
    }
}

const person = new Person(30);

// Accessing a private property directly would result in an error
console.log(person.age); // Error: Property 'age' is private and only accessible within class 'Person'.

// Accessing the age using the getAge method is allowed
console.log(person.getAge()); // 30

In this example, the age property is marked as private, making it inaccessible from outside the Person class. We provide a public method getAge to access the age property’s value.

Inheritance and Abstract Classes

Inheritance

Inheritance is a fundamental OOP concept that allows you to create a new class (subclass) based on an existing class (superclass). Subclasses inherit properties and methods from their superclasses and can also extend or override them.

class Animal {
    makeSound() {
        console.log("Animal makes a sound");
    }
}

class Dog extends Animal {
    makeSound() {
        console.log("Dog barks");
    }
}

const animal = new Animal();
const dog = new Dog();

animal.makeSound(); // "Animal makes a sound"
dog.makeSound();    // "Dog barks"

In this example, the Dog class extends the Animal class and overrides the makeSound method.

Abstract Classes

Abstract classes serve as base classes for other classes but cannot be instantiated directly. They can contain abstract methods that must be implemented by derived classes.

abstract class Shape {
    abstract getArea(): number;
}

class Circle extends Shape {
    constructor(private radius: number) {
        super();
    }

    getArea(): number {
        return Math.PI * this.radius ** 2;
    }
}

const circle = new Circle(5);
console.log(circle.getArea()); // 78.53981633974483

In this example, the Shape class is an abstract class with an abstract method getArea. The Circle class extends Shape and provides an implementation for getArea.

Interfaces vs. Abstract Classes

Interfaces

  • Interfaces define contracts for objects.
  • They can be implemented by multiple classes.
  • Interfaces cannot contain any implementation, only method signatures and property declarations.
  • They are used for defining structure and ensuring that classes adhere to a specific contract.

Abstract Classes

  • Abstract classes can serve as base classes for other classes.
  • They can contain both abstract and non-abstract methods.
  • Abstract classes can have constructor implementations.
  • They are used when you want to provide a common base for related classes with shared functionality.

Choosing between interfaces and abstract classes depends on your design needs. Use interfaces when you want to define contracts for objects, and use abstract classes when you need to provide a common base for related classes.

Conclusion

Classes and object-oriented programming are fundamental concepts in TypeScript for creating reusable and structured code. By defining classes, using constructors, and working with properties, you can encapsulate data and behavior into well-organized units. Understanding access modifiers further allows you to control the visibility and accessibility of class members, contributing to code safety and maintainability.

Methods and access modifiers, inheritance and abstract classes, and interfaces vs. abstract classes are important concepts in TypeScript for building well-structured and organized object-oriented programs. These concepts enable you to create reusable, maintainable, and flexible code that adheres to principles of object-oriented design. Understanding when to use each of these features is essential for effective TypeScript development.

Previous
Next