DEV Community

Haddad Zineddine
Haddad Zineddine

Posted on

Learn TypeScript — The Ultimate Beginners Guide : Object-oriented Programming

Typescript OOP

1. Object-oriented Programming

As we know JavaScript does'nt have the concept of classes like other programming languages such as ( PHP, Java, C++, C# ... ).

with ES6 you can defined classes but it's just a syntactic sugar for creating constructor function and prototypal inheritance.

Let's see OOP in TypeScript :

1- Creating Classes and objects :

class Account {
  id: number;
  owner: string;
  balance: number;

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

  deposit(amount: number): void {
    if (amount > 0) {
      this.balance += amount;
    }

    throw new Error("Invalid amount");
  }
}

let account = new Account(1, "zineddine", 100);

account.deposit(100);

console.log(typeof account); // object
console.log(account instanceof Account); // true

/*

always make sure to use instanceof property to check if 
an object is an instance of a class

*/
Enter fullscreen mode Exit fullscreen mode

Note : You can't use the function keyword inside a class to declare a function, use it only when you declare a stand-alone function.

2- Read-only and Optional Properties :

class User {
  readonly id: number;
  name: string;
  email: string;
  nickname?: string; // optional property

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

let user = new User(1, "zineddine", "hz_haddad@esi.dz");
user.id = 12; // Cannot assign to 'id' because it is a read-only property
Enter fullscreen mode Exit fullscreen mode

3- Access Control Keywords :

class Account {
  /*
    public # by default
    private
    protected
  */

  id: number;
  private _balance: number;

  constructor(id: number, balance: number) {
    this.id = id;
    this._balance = balance;
  }

  deposit(amount: number): void {
    if (amount > 0) {
      // assume we want also to log the transaction
      this._balance += amount;
    }

    throw new Error("Invalid amount");
  }

  private calculateTax(amount: number): number {
    return amount * 0.1;
  }

  getBalance(): number {
    return this._balance;
  }
}

let account = new Account(1, 100);
account._balance -= 50; // Property '_balance' is private and only accessible within class 'Account'
Enter fullscreen mode Exit fullscreen mode

4- Parameter Properties and Getters & Setters :

class Account {
  nickname?: string; // optional property

  constructor(
    public readonly id: number,
    public owner: string,
    private _balance: number
  ) {}

  get balance(): number {
    return this._balance;
  }

  set balance(value: number) {
    if (value < 0) {
      throw new Error("Balance cannot be negative");
    }
    this._balance = value;
  }
}

let account = new Account(1, "zineddine", 100);

console.log(account.balance); // 100
account.balance = -100; // throws error
account.balance = 100; // OK
Enter fullscreen mode Exit fullscreen mode

5- Index Signatures :

Index Signatures are just a fancy name for dynamic properties

class NameByNumber {
  // index signature property
  [name: string]: number;
}

let nameByNumber = new NameByNumber();

nameByNumber.John = 1;
// nameByNumber.['John'] = 1;
// nameByNumber.John = '1'; Type 'string' is not assignable to type 'number'
nameByNumber.Jane = 2;
nameByNumber.Bob = 3;

console.log(nameByNumber.John); // 1
Enter fullscreen mode Exit fullscreen mode

6- Static Members :

class Ride {
  private static _activeRides: number = 0;

  start() {
    Ride._activeRides++;
  }

  end() {
    Ride._activeRides--;
  }

  static get activeRides() {
    return Ride._activeRides;
  }
}

let ride1 = new Ride();
let ride2 = new Ride();

ride1.start();
ride2.start();

console.log(Ride.activeRides); // 2
Enter fullscreen mode Exit fullscreen mode

7- Inheritance and Methods Overriding :

class Person {
  constructor(public firstName: string, public lastName: string) {}

  get fullName() {
    return this.firstName + " " + this.lastName;
  }

  walk() {
    console.log("Walking");
  }
}

class Student extends Person {
  constructor(firstName: string, lastName: string, public id: number) {
    super(firstName, lastName);
  }

  override walk() {
    super.walk();
    console.log("Walking on the stairs");
  }

  override get fullName() {
    return "Student : " + super.fullName;
  }
}

let student = new Student("John", "Doe", 123);

console.log(student.fullName);
student.walk();

/*

  Walking
  Walking on the stairs

*/

console.log(student instanceof Person); // true
Enter fullscreen mode Exit fullscreen mode

8- Polymorphism :

// parent class , base class , super class
class Person {
  protected steps: number = 0;

  constructor(public firstName: string, public lastName: string) {}

  get fullName() {
    return this.firstName + " " + this.lastName;
  }
}

// child class , sub class , derived class
class Student extends Person {
  constructor(firstName: string, lastName: string, public id: number) {
    super(firstName, lastName);
  }

  override get fullName() {
    return "Student : " + super.fullName;
  }
}

class Teacher extends Person {
  constructor(firstName: string, lastName: string, public id: number) {
    super(firstName, lastName);
  }

  override get fullName() {
    return "Teacher : " + super.fullName;
  }
}

function printName(persons: Person[]) {
  for (let person of persons) {
    console.log(person.fullName);
  }
}

printName([
  new Person("John", "Doe"),
  new Student("Jane", "Doe", 123),
  new Teacher("John", "Doe", 123),
]);

/*

John Doe
Student : Jane Doe
Teacher : John Doe

*/
Enter fullscreen mode Exit fullscreen mode

9- Abstract Classes :

abstract class Shape {
  constructor(public color: string) {}

  abstract render(): void;
}

class Circle extends Shape {
  constructor(public radius: number, color: string) {
    super(color);
  }

  override render(): void {
    console.log("Circle");
  }
}

let shape = new Shape("red"); // Cannot create an instance of an abstract class
Enter fullscreen mode Exit fullscreen mode

10- Interfaces :

interface Calender {
  name: string;
  addEvent(event: string): void;
  removeEvent(event: string): void;
}

interface CloudCalender extends Calender {
  sync(): void;
}

class GoogleCalender implements CloudCalendar {
  constructor(public name: string) {}

  addEvent(event: string): void {
    console.log(`Adding ${event} to GoogleCalendar`);
  }
  removeEvent(event: string): void {
    console.log(`Removing ${event} from GoogleCalendar`);
  }
  sync(): void {
    console.log("Syncing GoogleCalendar");
  }
}
Enter fullscreen mode Exit fullscreen mode

Note : In TypeScript, interfaces and type aliases can be used interchangeably.
Both can be used to describe the shape of an object

interface Person {
  name: string;
}

let person: Person = {
  name: "Zineddine",
};

type User = {
  name: string;
};

let user: User = {
  name: "Zineddine",
};
Enter fullscreen mode Exit fullscreen mode

That’s it for the this chapter !

Github link : TypeScript-Fundamentals-in-One-Place

Top comments (0)