TypeScript Crashcourse

2 Maret 2020

Basic Typing

There are 3 basic types in TypeScript

var isDone: boolean = false;
let lines: number = 69;
const name: string = 'Jajang';

But you can omit the type annotation if the variables are derived from explicit literals

var isDone = false;
let lines = 69;
const name = 'Jajang';

When it's impossible to know, there is the any type

let notSure: any = 4;
notSure = 'maybe a string instead';
notSure = false;    // okay, definitely a boolean

Use const keyword for constants

const numLivesForCat = 9;
numLivesForCat = 1; // Error

For collections, there are typed arrays and generic arrays

let list: number[] = [1, 2, 3];

// Or, using the generic array type
let list: Array<number> = [1, 2, 3];

For enumerations

enum Color { Red, Yellow, Green };
let c: Color = Color.Green;

if (c === Color.Green) {
    console.log('Lets go!');
}

Lastly, void is used in the special case of a function returning nothing.

function bigHorribleAlert(): void {
  alert('I'm a little annoying box!');
}

Functions

Functions are first class citizens, support the lambda 'fat arrow' syntax and use type inference.

The following are equivalent, the same signature will be inferred by the compiler, and same JavaScript will be emitted

Regular function

// Function Declaration
function f1(i: number): number {
return i * i;
}

// Function Expression let f1 = function (i: number): number { return i * i; }

Return type inferred

let f2 = function (i: number) {
  return i * i;
}

'Fat arrow' syntax

let f3 = (i: number): number => {
return i * i;
}

'Fat arrow' syntax with return type inferred

let f4 = (i: number) => { return i * i; }

'Fat arrow' syntax with return type inferred, braceless means no return keyword needed.

let f5 = (i: number) => i * i;

var, let, and const

Declaring a variable using the above keywords:

  • Both type and initial value.

    var width:number = 100;
    let height:number = 200;
    const key:string = 'abc123';
  • Without type, but with an initial value.

    var width = 100;
    let height = 200;
    const key = 'abc123';
  • Only the type.

    var width: number;
    let height: number;
    // const does not support without initial value
  • Without type and initial value.

    var width;
    let height;
    // const does not support without initial value

Variable Scoping

void leFn() {
    std::string umurWawan = 25;
    std::cout << umurWawan; // ok
}

void leOtherFn() {
    std::cout << umurWawan; // WaWAn saHA ANyI...
}

var is Function Scoped

function someFn() {   

  if (true) {        

    // defined locally
    // its scope ends where curly braces ends
    var local = 1000;

    console.log(local);   //ok

  }

  console.log(local);     //ok

  function nested() {         
    console.log(local);   //ok
  }

}

console.log(local);       //error

let and const are Block Scoped

function someFn() {   

  if (true) {        

    // defined locally
    // its scope ends where curly braces ends
    let local = 1000;

    console.log(local);   // ok
  }

  console.log(local);     //error

  function nested() {         
    console.log(local);   //error
  }

}

console.log(local);       //error

Interfaces

Interfaces are structural, anything that has the properties is compliant with the interface.

interface Person {
  name: string;

  // Optional properties, marked with a '?'
  age?: number;

  // And of course functions
  move(): void;
}

Object that implements the Person interface can be treated as a Person since it has the name and move properties

let p: Person = {
  name: 'Bobby',
  move: () => { }
};

let validPerson: Person = {
  name: 'Bobby',
  age: 42,    // optional property
  move: () => { }
};

Object below is not a person because age is not a number and there is no move function.

let invalidPerson: Person = {
  name: 'Bobby',
  age: true
};

Interfaces can also describe a function type

interface SearchFunc {
  (source: string, subString: string): boolean;
}

Only the parameters' types are important, names are not important.

let mySearch: SearchFunc;

mySearch = function (src: string, sub: string) {
  return src.search(sub) != -1;
}

Classes

Class members are public by default

class Point {
  // Properties
  x: number;

  /* Constructor - the public/private keywords 
   * in this context will generate the boiler 
   * plate code for the property and the 
   * initialization in the constructor.
   *
   * In this example, 
   * 'y' will be defined just like 'x' is,
   * but with less code
   * 
   * Default values are also supported
   */

  constructor(x: number, public y: number = 0) {
    this.x = x;
  }

  // Functions
  dist() {
    return Math.sqrt(this.x * this.x + this.y * this.y);
  }

  // Static members
  static origin = new Point(0, 0);
}
let p1 = new Point(10, 20);
let p2 = new Point(25);   //y will be 0

Classes can be explicitly marked as implementing an interface. Any missing properties will then cause an error at compile-time.

class PointPerson implements Person {
  name: string;
  move() {}
}

Class inheritance

class Point3D extends Point {
  constructor(x: number, y: number, public z: number = 0) {
    // Explicit call to the super class constructor 
    // is mandatory
    super(x, y);
  }

  // Override
  dist() {
    let d = super.dist();
    return Math.sqrt(d() * d() + this.z * this.z);
  }
}

Generics

Classes

class Tuple<T1, T2> {
  constructor(public item1: T1, public item2: T2) {}
}

Interfaces

interface Pair<T> {
  item1: T;
  item2: T;
}

And functions

let pairToTuple = function <T>(p: Pair<T>) {
  return new Tuple(p.item1, p.item2);
};
let tuple = pairToTuple({
  item1: 'hello',
  item2: 'world'
});

Template strings

Template Strings: strings that use backticks (`).

String Interpolation with Template Strings

let name = 'Tyrone';
let greeting = `Hi ${name}, how are you?`

Multiline Strings with Template Strings

let multiline = `This is an example
of a multiline string`;

Iterators

  • for..of statement. Iterate over the list of values on the object being iterated.

let arrayOfAnyType = [1, 'string', false];
for (const val of arrayOfAnyType) { console.log(val); // 1, 'string', false }

let list = [4, 5, 6];
for (const i of list) {
  console.log(i); // 4, 5, 6
}

let arrayOfAnyType = [1, 'string', false];

for (const val of arrayOfAnyType) { 
  console.log(val); // 1, 'string', false 
}

let list = [4, 5, 6];
for (const i of list) { console.log(i); // 4, 5, 6 }
  • for..in statement. Iterate over the list of keys on the object being iterated.

for (const i in list) {
   console.log(i);    // 0, 1, 2
}
  • Higher order functions

let arrayOfAnyType = [1, 'string', false];
arrayOfAnyType.forEach(i => console.log(i)); // 1, 'string', false
const names = ['Ujang', 'Supardi', 'Wawan'] 
names.forEach((name: string) => { 
    console.log(Halo, selamat datang ${name}); 
})

More Types

  • Union Type (|)

let code: string | number;
code = 123;     // ok
code = 'ABC';   // ok
code = false;   // compiler error
  • Intersection Types (&)

interface Animal {
    kind: string;
}

interface Person { 
    firstName: string; lastName: string; age: number; 
}

interface Employee { 
    employeeCode: string; 
}

let employee: Animal & Person & Employee = { 
    kind: 'human', 
    firstName: 'Jane', 
    lastName: 'Smith', 
    age: 20, 
    employeeCode: '123' 
}

Last updated