Class

Basics

Like Java

Constructor

    • constructor(public publicProperty: type) - shorthand to declare both parameter and property
    • child constructor must call super()
    • before super() cannot access 'this'

Inheritance

  • call parent method
    • call instance method call the implementation by instance value, not variable declaration
    • super.superMethod()
  • 'abstract - like Java

Property Modifiers (static, public, private, protected, readonly)

  • static - like Java
  • visibility
    • public by default
    • private name: string; - a private member, accessible by class but checked for compatibility
    • protected - accessible by class and deriving classes
  • readonly:
    • must be initialized at declaration or in constructor

Accessors

(ECMAScript 5+)

    • get fullName(): string {...}
    • set fullName(newName: string) {..}

Accessors are automatically 'readonly'

Advanced: Constructor Functions (indepth understanding of class/instance/'typeof')

class T{}:

    • T used as value is in fact a constructor function
      • as value T can be assigned to other variable
    • However T is not a variable therefore cannot be re-assigned
    • T used as type (let varT : T) specifies the instances of the class (instanceOfT instanceof T === true)

What 'new' actually do:

  1. creates a new object ('this')
  2. sets the prototype of 'this' object to the constructor function's prototype property (note the difference of 'prototype of x' and 'prototype property of x')
  3. binds the 'this' keyword to the 'this' object and executes the constructor function
  4. returns the object

'typeof' T (where T is a class):

  • used as value, typeof T === 'function'
  • used as type, specifies the 'public face' of T
class T {
    static staticP = 'p'
    tellStaticP() {
        console.log(T.staticP)
    }
}
// T is in fact a constructor function
console.log(typeof T) // function
// 'typeof' used as value returns a string
console.log(typeof(typeof T)) // string
console.log(typeof T === 'function') // true


// what is an instance of T?
let instanceOfT : T
instanceOfT = new T()
console.log(typeof instanceOfT) // object
console.log(instanceOfT instanceof T) // true
console.log(Object.getPrototypeOf(instanceOfT)) // T{}
console.log(Object.getPrototypeOf(instanceOfT) === T.prototype) // true
console.log(Object.getPrototypeOf(instanceOfT).constructor === T) // true
console.log(Object.getPrototypeOf(instanceOfT).constructor.staticP === T.staticP) // true
console.log(Object.getPrototypeOf(instanceOfT).tellStaticP === instanceOfT.tellStaticP) // true

// let t2: T = T   // Compile error: Property 'tellStaticP' is missing in type 'typeof T' but required in type 'T'
// the line above does not work, because 'T' as type means an instance of T, therefore assigning T, the constructor function, 
// is an error because the instance of T requires a member function 'tellStaticP' at least in its prototypes
// SUMMARY: 'T' as a type specifies instance of T, with requirements (such as 'tellStaticP') to make a value assignable to 'T'
// SUMMARY: an instance is an object, which's prototype is the 'prototype' property of a function
// SUMMARY: the prototype has a 'constructor' property pointing to the constructor function
// SUMMARY: static member of class is attached to the class (the constructor function)
// SUMMARY: non-static (instance) method is attached to the prototype


console.log("===================================================")

// what is 'typeof T'?
let anotherNameOfSameT: typeof T // here 'typeof' being used as a type, not a value
anotherNameOfSameT = T
console.log(typeof anotherNameOfSameT) // function
console.log(anotherNameOfSameT instanceof T) // false
console.log(Object.getPrototypeOf(anotherNameOfSameT)) // [Function]
console.log(Object.getPrototypeOf(anotherNameOfSameT) === Function.prototype) // true
console.log(anotherNameOfSameT === T) // true
anotherNameOfSameT.staticP = 'new P'
let instanceOfNewT : T = new anotherNameOfSameT()
instanceOfT.tellStaticP() // new P
instanceOfNewT.tellStaticP() // new P
// SUMMARY: typeof T used as a type means the 'constructor function as a type'
// SUMMARY: since a class in typescript is just a constructor function, it can be changed in runtime

console.log("===================================================")
let anotherClassOfT: typeof T
anotherClassOfT = class {
    static staticP = 'another P'
    tellStaticP() {
        console.log("telling from anotherClassOfT, T.staticP: ", T.staticP) // new P
        console.log("telling from anotherClassOfT, my own staticP: ", Object.getPrototypeOf(this).constructor.staticP) // another P
    }
}
let instanceOfAnotherClassOfT : T = new anotherClassOfT()
instanceOfAnotherClassOfT.tellStaticP()
// SUMMARY: 'typeof T' as a type, is not exactly T (T is T), but type of constructor functions with those type checks
// SUMMARY: here another class can be assigned to a variable of 'typeof T', as long as the class satisfies those checks (required members)
// SUMMARY: so 'typeof T' as a type, is required 'public side signature' of constructor functions

// T = anotherClassOfT  // this does not work, T is not a variable

/*

FINAL SUMMARY:
class T{}                     // T is a constructor function
let typeofT = typeof T        // typeof T used as value, is a string, 'function'
let someClass : typeof T      // typeof T used as type, is the 'public face' of T, 
                              // so long other constructor function satisfies to this 'public face', it's assignable
 */

Advanced: using a class as an interface

First needs to understand the constructor function (see above)

Then since class name used as a type specifies the instance type, it can be used as an interface.

class Point {
    x: number;
    y: number;
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};

Example

class Student {
    fullName: string;
    constructor(public firstName: string, public middleInitial: string, public lastName: string) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}

class Clock implements ClockInterface {... // implement an interface

// extends
class Dog extends Animal {...
   constructor(.....){
      .......
      super(.....)

// abstract
abstract class Animal {
    abstract makeSound(): void;