DEV Community

Cover image for Exploring Object-Oriented Programming - TypeScript Examples
Mahabubur Rahman
Mahabubur Rahman

Posted on

Exploring Object-Oriented Programming - TypeScript Examples

Object-oriented programming (OOP) is a paradigm that allows developers to structure their code in a more organized and modular way, making it easier to manage and maintain. In this article, we'll explore some fundamental concepts of OOP—inheritance, polymorphism, abstraction, and encapsulation—through the lens of TypeScript, a popular statically typed superset of JavaScript. We'll delve into each concept with examples to illustrate their usage and benefits.

Inheritance

Inheritance is a mechanism in OOP that allows a class (subclass) to inherit properties and behaviors (methods) from another class (superclass). This promotes code reuse and establishes a hierarchy among classes. In TypeScript, inheritance is achieved using the extends keyword.

class Animal {
  constructor(public name: string) {}

  move(distanceInMeters: number = 0) {
    console.log(`${this.name} moved ${distanceInMeters}m.`);
  }
}

Enter fullscreen mode Exit fullscreen mode
class Dog extends Animal {
  bark() {
    console.log("Woof! Woof!");
  }
}

Enter fullscreen mode Exit fullscreen mode
const dog = new Dog("Buddy");
dog.bark(); // Output: Woof! Woof!
dog.move(10); // Output: Buddy moved 10m.

Enter fullscreen mode Exit fullscreen mode

In this example, the Dog class inherits the move method from the Animal class and extends it with its own method bark.

Polymorphism

Polymorphism allows objects of different classes to be treated as objects of a common superclass. It enables flexibility and extensibility in code by allowing methods to be overridden in subclasses. TypeScript supports polymorphism through method overriding.

class Shape {
  area(): number {
    return 0;
  }
}
Enter fullscreen mode Exit fullscreen mode
class Circle extends Shape {
  constructor(private radius: number) {
    super();
  }

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

Enter fullscreen mode Exit fullscreen mode
class Rectangle extends Shape {
  constructor(private width: number, private height: number) {
    super();
  }

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

Enter fullscreen mode Exit fullscreen mode
const shapes: Shape[] = [new Circle(5), new Rectangle(4, 6)];

shapes.forEach(shape => {
  console.log("Area:", shape.area());
});

Enter fullscreen mode Exit fullscreen mode

In this example, both Circle and Rectangle classes override the area method of the Shape class to calculate their respective areas.

Abstraction

Abstraction is the process of hiding complex implementation details and exposing only the necessary functionalities to the outside world. Abstract classes and methods in TypeScript facilitate abstraction.

abstract class Vehicle {
  constructor(public name: string) {}

  abstract move(): void;
}
Enter fullscreen mode Exit fullscreen mode
class Car extends Vehicle {
  move() {
    console.log(`${this.name} is driving.`);
  }
}
Enter fullscreen mode Exit fullscreen mode
class Plane extends Vehicle {
  move() {
    console.log(`${this.name} is flying.`);
  }
}
Enter fullscreen mode Exit fullscreen mode
const car = new Car("Toyota");
const plane = new Plane("Boeing");

car.move();   // Output: Toyota is driving.
plane.move(); // Output: Boeing is flying.

Enter fullscreen mode Exit fullscreen mode

Here, Vehicle is an abstract class with an abstract method move(). Subclasses Car and Plane provide concrete implementations of the move method.

Encapsulation

Encapsulation is the bundling of data (attributes) and methods that operate on that data into a single unit (class). It restricts direct access to the data from outside the class and promotes data hiding and abstraction. In TypeScript, encapsulation is achieved through access modifiers like public, private, and protected.

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

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

  displayInfo() {
    console.log(`ID: ${this.id}, Name: ${this.name}`);
  }
}

Enter fullscreen mode Exit fullscreen mode
const emp = new Employee(101, "John Doe");
console.log(emp.name);     // Output: John Doe
emp.displayInfo();         // Output: ID: 101, Name: John Doe
// console.log(emp.id);   // Error: Property 'id' is private and only accessible within class 'Employee'.

Enter fullscreen mode Exit fullscreen mode

In this example, id is a private member of the Employee class, accessible only within the class itself.

Conclusion

Understanding and applying the principles of inheritance, polymorphism, abstraction, and encapsulation are crucial for writing clean, maintainable, and scalable code. TypeScript's support for these OOP concepts enhances code readability and modularity, making it a powerful choice for building complex applications. By leveraging these features effectively, developers can write more robust and extensible software solutions.

Top comments (0)