What about OOP in Typescript 🤔A quick overview
Tags: typescript, oop, webdev, opensource
Published: 2023-03-30 12:40:21

## **Table of contents**

- [**Introduction**](#introduction)

- [**OOP Pillars**](#so-lets-start-with-the-4-pillars-of-oop-in-ts-😄)

  - [**Inheritance**](#inheritance)
        
  - [**Encapsulation**](#encapsulation)

  - [**Abstraction**](#abstraction)
        
  - [**polymorphism**](#polymorphism)
        
- [**References**](#references)

---

</br>

## **Introduction**

</br>

Hello devs 😄

As many of us know TypeScript is a superset of JavaScript that adds typing, classes, and interfaces to the language. These features make TypeScript a powerful language for OOP

TypeScript really excels when it comes to oop with JavaScript as It makes programming in an object-oriented fashion appear much like it does in other object-oriented languages such as C# or Java, .So devs who are familiar with those languages will easily and quickly learn typescript</br>
For example:

### **Private access modifier in JS**

```typescript
class Base {
  #x = 0;
  constructor() {}
}

const b = new Base();
console.log(b.x); // this line will log undefined
```

### **Private access modifier in TS**

```typescript
class Base {
  private x = 0; // Looks like C++ or Java Right 😄
  constructor() {}
}

const b = new Base();
console.log(b.x); //  this line will raise an error
```

> Property **x** is private and only accessible within class **Base**

</br>

### So let's start with the 4 pillars of OOP in TS😄

</br>

![OOP Pillars](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5nab148em9ayyyb5zi45.png)

</br>

## **Inheritance**

Inheritance is the ability to create new classes based on existing ones. In TypeScript, you can use the "extends" keyword to create a subclass that inherits properties and methods from a parent class. Here are some examples of inheritance in TypeScript:

</br>

#### **Simple Inheritance**

```typescript
class Animal {
  name: string;

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

  makeSound() {
    console.log("Generic animal sound");
  }
}

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

const myDog = new Dog("Buddy");

console.log(myDog.name); // Output: Buddy

myDog.makeSound(); // Output: Woo!
```

</br>

#### **Multiple Inheritance**

- In TypeScript, we can’t inherit or extend from more than one class, but [**Mixins**](https://www.typescriptlang.org/docs/handbook/mixins.html) helps us to get around that.

- [**Mixins**](https://www.typescriptlang.org/docs/handbook/mixins.html) create partial classes that we can combine to form a single class that contains all the methods and properties from the partial classes you can check documentation thus here i am trying to focus on main and basic concepts of OOP .

</br>
</br>

## **Encapsulation** 📬 📫

Encapsulation is the way of hiding the internal details of an object and exposing only what is necessary and what you specify . In TypeScript, you can use access modifiers like public, private, and protected to control access to class members.</br>
Here are some examples of encapsulation in TypeScript:

</br>

#### **Example 1: Private & public Access Modifiers**

```typescript
class Person {
  private name: string;

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

  public greet() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

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

</br>

> - **greet** method is a public method can be accessed anywhere.</br>
> - Property **name** is private so it isn't accessible outside the class.

</br>

#### **Example 2: Protected Access Modifier**

```typescript
class Animal {
  protected name: string;

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

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }

  public bark() {
    console.log(`Woo, my name is ${this.name}.`);
  }
}

const dog = new Dog("Buddy");
dog.bark(); // Output: Woo, my name is Buddy.
console.log(dog.name); // Error:
```

> - **bark( )** method can access the protected member name as it is inside the child class dog
> - Property **name** is protected and only accessible within class **Animal** and its subclasses</br>

</br>

## **Abstraction**

Abstraction identifies only the required characteristics of an object while ignoring how to implement details. In TypeScript, you can use abstract classes and Interfaces to implement abstraction concept.

</br>
<a name="#abstractClasses"></a>
#### **Abstract classes**

```typescript
abstract class Animal {
  name: string;

  constructor(name: string) {
    this.name = name;
  }
  abstract makeSound(): void;
  move(distanceInMeters: number) {
    console.log(`Animal moved ${distanceInMeters}m.`);
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
  makeSound() {
    console.log("Woo!");
  }
}

const myDog = new Dog("Buddy");
console.log(myDog.name); // Output: Buddy
myDog.move(10); // Output: Animal moved 10m.
myDog.makeSound(); // Output: Woo!
```

> :memo: **Note:**
>
> - The class which implements an abstract class must call **super( )** in the constructor.
> - you have to implement abstract methods like **makeSound** that are extended from abstract classes

</br>

#### **Interfaces**

Generally, Interfaces serve as a contract in code. it’s all or nothing. When you implement an interface, you must implement everything defined in that interface methods to implement abstraction. Here's an example:

```typescript
interface Animal {
  name: string;
  makeSound(): void;
}

class Dog implements Animal {
  name: string;

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

  makeSound() {
    console.log("Woo!");
  }
}

const myDog = new Dog("Buddy");
console.log(myDog.name); // Output: Buddy
myDog.makeSound(); // Output: Woo!
```

> - :warning: In case we missed to implement whether the property **name** or method **makeSound( )** we will get an error

</br>

## **polymorphism**

Polymorphism is the ability of method to have different forms, whether toy are backend of frontend you are going to use Polymorphism may be

- In Database Access: For example, a SQL database and a NoSQL database can both implement a common database interface and be used in the same way. This makes it easy to switch between different types of databases without changing the code that accesses the database.


- Polymorphism can be represented by Overriding or Overloading.

</br>

#### **Overriding**

```typescript
class Animal {
  name: string;

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

  makeSound() {
    console.log("Generic animal sound.");
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }
  makeSound() {
    console.log("Woo!");
  }
}

class Cat extends Animal {
  makeSound() {
    console.log("Meow!");
  }
}

function makeAnimalSound(animal: Animal) {
  animal.makeSound();
}

const myDog = new Dog("Buddy");
const myCat = new Cat("Whiskers");

makeAnimalSound(myDog); // Output: Woo!
makeAnimalSound(myCat); // Output: Meow!
```

> Base class **Animal** has **makeSound( )** method, subclasses **Cat** and **Dog** extend **Animal** have same method but with the overridden version

</br>

#### **Overloading**

Function Overloading with a different number of parameters and different types along with the same function name is **not supported** in normal way like :

```typescript
class Greeter {
  message: string;

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

  // Overload signatures
  greet(personName: string): string {
    return `${this.message}, ${personName}!`;
  } // Duplicate function implementation error

  greet(persons: string[]): string[] {
    return persons.map((personName) => `${this.message}, ${personName}!`);
  } // Duplicate function implementation error
}
```

I think As plain javascript couldn't differ between the overloaded methods as it doesn't support types, we have to do some work manually to check types of parameters in implementation.

### **So How can we implement overloading ?**

</br>

1. By defining a few overload signatures and one implementation signature.

```typescript
class Greeter {
  message: string;

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

  // Overload signatures
  greet(person: string): string;
  greet(persons: string[]): string[];
}
```

2. The implementation signature has more generic parameter and return types and implements functionality.
   </br>

**Then our class become:**

```typescript
class Greeter {
  message: string;

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

  // Overload signatures
  greet(person: string): string;
  greet(persons: string[]): string[];

  // Implementation signature
  greet(person: unknown): unknown {
    if (typeof person === "string") {
      return `${this.message}, ${person}!`;
    } else if (Array.isArray(person)) {
      return person.map((name) => `${this.message}, ${name}!`);
    }
    throw new Error("Unable to greet");
  }
}

const hi = new Greeter("Hi");

hi.greet("Angela"); // Output 'Hi, Angela!'
hi.greet(["Pam", "Jim"]); // Output ['Hi, Pam!', 'Hi, Jim!']
```

> :memo: **Note:**
> implementation signature is not callable. Only the overload signatures are callable.

```typescript
greet("World"); // Overload signature is callable
greet(["Jane", "Joe"]); // Overload signature is callable

const someValue: unknown = "Unknown";
greet(someValue); // Error as implementation signature is NOT callable
```

Thank you for reading i hope you enjoyed and I hope this will help someone better understand Object Oriented Programming with TypeScript :smile:

I will be happy if you share with me your comments and knowledge 😁

## **References**

- [Classes in Typescript](https://www.typescriptlang.org/docs/handbook/2/classes.html)

- [Abstract Classes](https://www.tutorialsteacher.com/typescript/abstract-class#:~:text=The%20class%20which%20implements%20an,super()%20in%20the%20constructor.)

- [Function Overloading](https://www.tutorialsteacher.com/typescript/function-overloading)