OOP In TypeScript

OOP In TypeScript

Creating A Class

We can create a class like this:

class Account {
    readonly id: number; // Setting type of the property
    owner: string;
    private _balance: number; // Only accessible from inside of class (private should start with _ )
    nickname?: string; // optional modifier

    // Initialing the properties
    constructor(id: number, owner: string, balance: number) {
        this.id = id;
        this.owner = owner;
        this._balance = balance;
    }

    // A method inside the class
    deposit(amount: number): void {
        if (amount <= 0) throw new Error("Invalid Amount");

        this._balance += amount;
    }

    // A private function only available inside class
    private calculateTax(): number {
        return this._balance * 0.2;
    }

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

let account = new Account(1, "Nima", 50);
account.deposit(50);

console.log(account.getBalance()); // return this._balance

Cleaning Constructors ! ! !

These are called parameter properties. Defining constructors are really bad at this moment but we will going to clean them. This is the code above but much cleaner

class Account {
    nickname?: string;

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

    deposit(amount: number): void {
        if (amount <= 0) throw new Error("Invalid Amount");

        this._balance += amount;
    }

    private calculateTax(): number {
        return this._balance * 0.2;
    }

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

let account = new Account(1, "Nima", 50);
account.deposit(50);

console.log(account.getBalance());

Getters & Setters

We can access to a private property from outside with getters and setters

class Account {
    nickname?: string;

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

    get balance(): number { // Will get the private property 
        return this._balance;
    }

    set balance(value: number) { // Will set the private property 
        if (value <= 0) throw new Error("Invalid Value");

        this._balance = value;
    }
}

let account = new Account(1, "Nima", 50);

console.log(account.balance); // we can get the property value here
account.balance = 1; // we can access and change its property value here

Index Signature

we can define a situation that can create properties for a objects like:

class SeatsAssignments {
    [seatNumber: string]: string;
}

let seats = new SeatsAssignments();

seats.a1 = "Nima";

// Using the bracket notation and can pass variable
seats["a2"] = "Mosh";

Static Members

We can define properties that they are belong to exact class not the cloned objets

class Ride {
    // Using (static) we say we want (_activeRides) belong to the class not objects
    static _activeRides: number = 0;

    start() {
        Ride._activeRides++;
    }

    stop() {
        Ride._activeRides--;
    }
    // with defining static we say _activeRides belongs to Ride class not the object
    static get activeRides(): number {
        return Ride._activeRides;
    }
}

let ride1 = new Ride(); // This will create an object
let ride2 = new Ride();

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

console.log(Ride.activeRides); // this will read from Ride Class (Liek global place)

Inheritance

we can define multiple methods in parent class and use them from child classes

class Person {
    constructor(public firstname: string, public lastname: string) {}

    get fullName(): string {
        return this.firstname + " " + this.lastname;
    }

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

class Teacher extends Person {
    // Overriding the fullName from The parnt Class using (override) keyword
    override get fullName(): string {
        return "Professor " + super.fullName; // Here We used super.(method) to get method from top(Parent) class
    }
}

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

let student = new Student(1, "Nima", "Prmi");
let teacher = new Teacher("Mosh", "Hamedani");

Ploymorphism

We define that a function run with many forms of classes

/***** START Same Code as Top Code */
class Person {
    constructor(public firstname: string, public lastname: string) {}

    get fullName(): string {
        return this.firstname + " " + this.lastname;
    }

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

class Teacher extends Person {
    // Overriding the fullName from The parnt Class using (override) keyword
    override get fullName(): string {
        return "Professor " + super.fullName; // Here We used super.(method) to get method from top(Parent) class
    }
}

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

/***** END Same Code as Top */

class Principle extends Person {
    override get fullName(): string {
        return "Principle " + super.fullName;
    }
}

// Polymorphismed call
printNames([
    new Student(1, "Nima", "Prmi"), // Here we have shape of the Student object(class)
    new Teacher("Mosh", "Hamedani"), // Here we have shape of the Teacher object(class)
    new Principle("Mary", "Weather"),
]);

// It is polymorphism
function printNames(people: Person[]) {
    for (let person of people) console.log(person.fullName);
}

Abstract Classes & methods

we can create abstracted classes and method and they will be not available to call outside but can be extended from a child class and change from childs. Also can not be functional inside that class (not the child i mean — Class itself)

// This class will not available from calling outside
// it is like a uncooked meal!
abstract class Shape {
    constructor(public color: string) {}

    abstract render(): void; // abstract methods only can be in abstract classes
}

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

    override render(): void {
        console.log("Rendering a circle");
    }
}

let shape1 = new Circle(5, "red");
shape1.render();

Interfaces & Abstract Classes

With interfaces we can create different shapes of objects. They are so cleaner to use and interfaces will render inside of compile time but abstract classes are available in runtimes as well.

In abstract classes we can define the main method functionality but in interface we can not define methods functionality

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

    abstract addEvent(): void;
    protected removeEvent(): void {
        console.log("Remove CalendarClass");
    }
}

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

interface CloudCalendar extends Calendar {
    sync(): void;
}

class GoogleCalendar extends CalendarClass {
    constructor(public name: string) {
        super(name);
    }

    sync(): void {
        console.log("Hello");
    }

    addEvent(): void {
        console.log(this.removeEvent());
    }
}

class MicrosoftCalendaar implements Calendar {
    constructor(public name: string) {}

    addEvent(): void {
        throw new Error("Method not implemented.");
    }
    removeEvent(): void {
        throw new Error("Method not implemented.");
    }
}

let calendar = new GoogleCalendar("google");
let microCalendar = console.log(calendar.addEvent());

Leave a Reply

Required fields are marked *