Classes in TypeScript

Classes in TypeScript

This article explains classes in TypeScript.

YouTube Video

Classes in TypeScript

Classes in TypeScript are based on JavaScript's ES6 classes and offer additional features like type annotations and access modifiers. This allows you to leverage the concepts of object-oriented programming while ensuring more robust and clear type safety.

Below are explanations of the basic usage and features of classes in TypeScript.

Basic Class Definition

 1class Person {
 2    name: string;  // Member variable
 3    age: number;   // Member variable
 4
 5    // Constructor
 6    constructor(name: string, age: number) {
 7        this.name = name;
 8        this.age = age;
 9    }
10
11    // Method
12    greet(): void {
13        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
14    }
15}
16
17const person = new Person("Alice", 25);
18person.greet();  // Hello, my name is Alice and I am 25 years old.
  • name and age are properties (member variables) of the class.
  • The constructor is a method called when creating an instance of a class, which takes arguments and assigns values to properties.
  • greet is a method of the class, indicating that it has no return value by being of void type.

Access Modifiers

In TypeScript, you can use access modifiers (public, private, protected) to control access to class properties and methods.

public

By default, all properties and methods are public. This means they can be accessed from outside the class.

 1class Animal {
 2    public species: string;
 3
 4    constructor(species: string) {
 5        this.species = species;
 6    }
 7
 8    public makeSound(): void {
 9        console.log(`${this.species} makes a sound.`);
10    }
11}
12
13const animal = new Animal("Dog");
14console.log(animal.species);  // Dog
15animal.makeSound();           // Dog makes a sound.
  • The species property and makeSound method are declared as public and can be accessed from outside the class.

private

Using the private modifier prevents access to the properties or methods from outside the class.

 1class Car {
 2    private brand: string;
 3
 4    constructor(brand: string) {
 5        this.brand = brand;
 6    }
 7
 8    public getBrand(): string {
 9        return this.brand;
10    }
11}
12
13const car = new Car("Toyota");
14// console.log(car.brand);  // Error: 'brand' is private and cannot be accessed.
15console.log(car.getBrand());  // Toyota
  • The brand property is declared as private, so it cannot be accessed from outside the class.
  • Encapsulating data can be achieved by hiding properties with the private modifier.

protected

The protected modifier restricts access from outside the class but allows it in subclasses (derived classes).

 1class Vehicle {
 2    protected model: string;
 3
 4    constructor(model: string) {
 5        this.model = model;
 6    }
 7}
 8
 9class Truck extends Vehicle {
10    public getModel(): string {
11        return this.model;
12    }
13}
14
15const truck = new Truck("Ford F-150");
16console.log(truck.getModel());  // Ford F-150
17
18// console.log(truck.model);
19// Error: Property 'model' is protected and only accessible within class 'Vehicle' and its subclasses.
  • The model property is declared as protected, so it cannot be accessed from outside the class, but can be accessed from subclasses.

Getters and Setters

In TypeScript, you can define getters and setters using the get and set keywords to retrieve and set property values.

 1class Employee {
 2    private _salary: number;
 3
 4    constructor(salary: number) {
 5        this._salary = salary;
 6    }
 7
 8    // Getter
 9    get salary(): number {
10        return this._salary;
11    }
12
13    // Setter
14    set salary(newSalary: number) {
15        if (newSalary > 0) {
16            this._salary = newSalary;
17        } else {
18            console.log("Salary must be positive.");
19        }
20    }
21}
22
23const employee = new Employee(50000);
24console.log(employee.salary);  // 50000
25employee.salary = 60000;
26console.log(employee.salary);  // 60000
27employee.salary = -100;        // Salary must be positive.
  • In this example, a getter and setter are used for the salary property to control external access and updates. The setter performs validation to prevent negative values, and displays a warning message if an invalid value is provided.

Inheritance

In TypeScript, classes can be inherited. Using the extends keyword, you can inherit functionality from a parent class.

 1class Animal {
 2    constructor(public name: string) {}
 3
 4    public move(): void {
 5        console.log(`${this.name} is moving.`);
 6    }
 7}
 8
 9class Bird extends Animal {
10    public fly(): void {
11        console.log(`${this.name} is flying.`);
12    }
13}
14
15const bird = new Bird("Sparrow");
16bird.move();  // Sparrow is moving.
17bird.fly();   // Sparrow is flying.
  • In this example, the Bird class inherits from the Animal class, which allows it to use the move method of Animal. Furthermore, it defines its own fly method, adding new functionality while inheriting features from the parent class.

Abstract Classes

Abstract classes (abstract) cannot be instantiated directly and are used as templates to provide concrete implementations in subclasses.

 1abstract class Shape {
 2    abstract getArea(): number;
 3
 4    public describe(): void {
 5        console.log("This is a shape.");
 6    }
 7}
 8
 9class Circle extends Shape {
10    constructor(private radius: number) {
11        super();
12    }
13
14    public getArea(): number {
15        return Math.PI * this.radius * this.radius;
16    }
17}
18
19const circle = new Circle(5);
20console.log(circle.getArea());  // 78.53981633974483
21circle.describe();  // This is a shape.
  • In this example, Shape is defined as an abstract class, and getArea is an abstract method that must be implemented by subclasses. The Circle class inherits this abstract class and implements its own getArea method to calculate the area of a circle. In addition, concrete methods like describe are inherited as common functionality and can be used as-is.

Relationship with Interfaces

Classes can implement interfaces, ensuring they have specific properties and methods.

 1interface Flyable {
 2    fly(): void;
 3}
 4
 5class Airplane implements Flyable {
 6    public fly(): void {
 7        console.log("The airplane is flying.");
 8    }
 9}
10
11const airplane: Flyable = new Airplane();
12airplane.fly();  // The airplane is flying.
  • In this example, the Flyable interface defines the specification for the fly method, and the Airplane class implements this interface by providing a concrete definition for the fly method. With this, any object that can be treated as a Flyable type is guaranteed to have a fly method.

Static Members

When you define static members in a class, those methods and properties are associated with the class itself. Static members can be called without instantiating the class.

 1class MathUtils {
 2    static PI: number = 3.14;
 3
 4    static add(a: number, b: number): number {
 5        return a + b;
 6    }
 7}
 8
 9console.log(MathUtils.add(10, 20)); // 30
10console.log(MathUtils.PI); // 3.14
  • You define static methods using the static keyword.
  • In this example, the MathUtils class defines a static method add and a static property PI.
  • Static members do not belong to class instances, but can be called directly from the class itself.

Summary

TypeScript classes add features like type safety, access modifiers, and abstract classes to JavaScript class functionality. This allows for more powerful and safer object-oriented programming.

You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.

YouTube Video