1. Advanced Type
1.1. Polymorphic this types
class Vehicle {
drive(): this {
// do something
if (this instanceof Car) {
console.log('car is driving');
}
return this;
}
}
let v = new Vehicle();
v.drive(); // returns Vehicle
class Car extends Vehicle {
carryPeople() {
// do something
return this;
}
}
let c = new Car();
c.drive().carryPeople(); // a fluent API
class Bus extends Vehicle {
pay() {
console.log('pay 2 yuan');
return this;
}
}
let b = new Bus();
c.pay().drive();
1.2. Declaration merging
The compiler merges two separate declarations declared with the same name into a single definition.
interface Employee {
name: string;
doWork: () => void;
}
interface Employee {
title: string;
phone: string;
}
// TypeScript Compiler will merge them:
interface Employee {
name: string;
doWork: () => void;
title: string;
phone: string;
}
Allowed merges:
- Interfaces
- Enums
- Namespaces
- Namespaces with enums
- Namespaces with functions
- Namespaces with classes
Disallowed merges:
- Classes with classes
1.3. Interface merging and module augmentation
// universityLibrarian.ts: think this is an older version or third party lib. You cannot modify but extend it.
export class UniversityLibrarian implements Interfaces.Librarian, Employee, Researcher {
name: string;
email: string;
department: string;
[CLASS_INFO](): void {
console.log('This class represents a UniversityLibrarian.');
}
static [Symbol.hasInstance](obj: Object) {
return obj.hasOwnProperty('name') && obj.hasOwnProperty('assistCustomer');
}
assistCustomer(customerName: string) {
console.log(this.name + ' is assisting ' + customerName);
}
assistFaculty() {
console.log('Assisting faculty.');
}
// implementation of the following to be provided by the mixing function
title: string;
addToSchedule: () => void;
logTitle: () => void;
doResearch: (topic: string) => void;
}
// new extension file: universityLibExt.ts
import { UniversityLibrarian } from './classes';
declare module './classes' {
export interface UniversityLibrarian {
phone: string;
hostSeminar(topic: string): void;
}
}
UniversityLibrarian.prototype.hostSeminar = function(topic) {
console.log('Hosting a seminar on ' + topic);
};
// app.ts
import { UniversityLibrarian } from './classes';
import 'universityLibExt'; // note: add ts suffix doesn't work
var u = new UniversityLibrarian();
u.hostSeminar('aya');
1.4. Type guards
1.4.1. typeof: type name only allow: "string, number, boolean, symbol"
let x: string | number = 12;
if (typeof x === 'string') {
// x is a string
} else {
// x is a number
}
1.4.2. instanceof: For class
class Phone {
callSomeone() {
console.log('call someone');
}
}
class Tablet {
watchMovie() {
console.log('watch movie');
}
}
const device: Phone | Tablet = new Phone();
if (device instanceof Phone) {
device.callSomeone();
}
1.4.3. * User-Defined Type Guard: For interface
interface Vehicle {
numberOfWheels: number;
}
function isVehicle(v: any): v is Vehicle {
return (<Vehicle>v).numberOfWheels !== undefined;
}
let c = new Car();
if (isVehicle(c)) {
// it's a vehicle
}
1.5. Symbols
- ES2015 feature
- Primitive data type
- Unique
- Immutable
let mySymbol = Symbol('first_symbol');
let anotherSymbol = Symbol('first_symbol');
// console.log(mySymbol === anotherSymbol); // false
// console.log(typeof mySymbol);
let myObject = {
[mySymbol]: 'value for my symbol key',
};
1.5.1. Use cases
- Unique Constants
- Computed Property Declarations
- Customize Internal Language Behavior