Skip to content

TS Classes

Hint compiler about the type of this

  • In a normal class, this is a reference to the class instance
  • But, on special occasions, this may refer to something else, and the compiler can’t know about it
  • example:
class Person {
    name: string;
    constructor(name: string) {
        this.name = name;
    }

    sayHello() {
        console.log(`Hello, I'm ${this.name}`);
    }
}

const me = new Person("John", 30);
me.sayHello(); // Hello, I'm John

const newMe = { sayHello: me.sayHello };
newMe.sayHello(); // Hello, I'm undefined (this refers to `newMe` which has no `name` property)
  • You can pass a special parameter called this to the methods of the Person class, telling the compiler that this is the instance of the Person class.
  • The compiler will complain if this value is not an instance of the Person class.
  • You are still able to call the method without passing this
  • example: hint compiler about this:
class Person {
    name: string;
    constructor(name: string) {
        this.name = name;
    }

    sayHello(this: Person) {
        // telling compiler `this` is now an instance of Person class
        console.log(`Hello, I'm ${this.name}`);
    }
}

const me = new Person("John", 30);
me.sayHello(); // Hello, I'm John

const newMe = { sayHello: me.sayHello };
newMe.sayHello(); // compiler will complain, `this` is not an instance of Person class
// you are still able to cal the method without passing `this` as `obj.sayHello()`

shorthand constructor initialization

  • Constructor initialization can have a lot of repetitive code.
  • normal situation:
class Person {
    private id: number;
    public name: string;
    constructor(id: string, name: string) {
        this.id = id;
        this.name = name;
    }
}
  • The shorthand constructor initialization is a shorter way to write the constructor.
  • You can use the shorthand syntax by specifying the modifier of all constructor parameters.
class Person {
    constructor(private id: string, public name: string) {
        // nothing else is needed,  the Person object will now have and `id` and `name` property coming from the constructor parameters.
    }
}

Access modifiers

  1. public: property accessed everywhere.
  2. private: property accessed only inside the class. not outside or in other classes that inherit from this class.
  3. readonly: property can only be read, not written.
  4. protected: property can be accessed in the class and in inherited classes. but not outside.
  5. abstract: only works with abstract classes, therefor the child classes must implement the abstract methods before instantiating the parent class.

JS Class inheritance notes

  • JS class can inherit from only one class.
  • If the child class does not have a constructor, it will inherit the parent class’s constructor.
  • The parent’s class constructor in the child class should be called first in the child constructor, using super().
  • Private properties can not be accessed by the child class.
  • Protected properties can be accessed by the child class.
  • abstract classes can not be instantiated, must be inherited first, then implemented.
  • abstract methods can have a signature in the abstract class, but they can not be declared.
  • a class can implement multiple interfaces.
  • a class can have more logic than the interface it implements, but the class must at least implement the methods of the interface.

Setters and getters

  • Setters and getters are used to set and get the value of a property.
  • Setters and getters are functions, but you don’t need to call them.
class Person {
    private _name: string;
    constructor(name: string) {
        this._name = name;
    }

    get name(): string {
        return this._name;
    }

    set name(str: string) {
        this._name = str;
    }

    get myName(): string {
        // getter, the name of the getter is the name of the property
        return this._name;
    }

    set myName(str: string) {
        // setter, the name of the setter is the name of the property
        this._name = str;
    }
}

const me = new Person("John");
console.log(me.name); // John, no need to call getter, it is used as normal property
me.name = "Jane"; // no need to call setter, it is used as normal assignment expression

// also
console.log(me.myName); // Jane, another way to access the property, using different getter
me.myName = "Doe"; // another setter for the same property _name

private constructor

  • private constructors enforce the singleton pattern on a class.
  • you can not instantiate the class directly, you must use the static method getInstance() to get the instance of the class.
  • in the getInstance() method, you can use the new keyword to instantiate the class, and call the private constructor.
  • such a class is called a singleton class, and can have a private static variable that is used to store the instance of the class.
class Person {
    private static instance: Person;
    private constructor(private name: string) {
        // nothing
    }

    static getInstance(): Person {
        if (!Person.instance) {
            Person.instance = new Person("John");
        }
        return Person.instance;
    }
}

const person = Person.getInstance(); // Person instance
const person2 = Person.getInstance(); // the same Person instance as above