Typescript Cheatsheet

Annotations with variables

Primitive :

    let apples = 5;  let speed: string = 'fast';  let hasName: boolean = true;  let nothingMuch: null = null;  let nothing: undefined = undefined;

Built in objects :

    let now: Date = new Date();

Array :

let colors: string[] = ['red', 'green', 'blue'];    let myNumbers: number[] = [1, 2, 3];    let truths: boolean[] = [true, true, false];

Classes :

    class Car {}    let car: Car = new Car();

Object literal :

    let point: { x: number; y: number } = {        x: 10,        y: 20    };

Function :

    const logNumber: (i: number) => void = (i: number) => {    console.log(i);    };

Type inference : If declaration and initialization are on the same line, typescript can infer the type.

        let speed: string = 'fast';    let speed = 'fast'; //equivalent

When to use annotations

Function that returns the 'any' type. any is a type used by typescript when it has no idea what the type can be. We should avoid variables with 'any'.

 const json = '{"x": 10, "y": 20}';        //JSON.parse return type any type        const coordinates: { x: number; y: number } = JSON.parse(json);        console.log(coordinates); // {x: 10, y: 20};
When we declare a variable on one line and initalizate it later
  let words = ['red', 'green', 'blue'];        let foundWord: boolean;        for (let i = 0; i < words.length; i++) {            if (words[i] === 'green') {                foundWord = true;            }        }
Variable whose type cannot be inferred correctly
let numbers = [-10, -1, 12];        let numberAboveZero: boolean | number = false;        for (let i = 0; i < numbers.length; i++) {            if (numbers[i] > 0) {                numberAboveZero = numbers[i];            }        }

Annotations with functions and objects

Annotations around functions

In:

    const logNumber: (i: number) => void = (i: number) => {        console.log(i);    };

the annotation is on the variable logNumber. Here we add annotations to the function itself. There is type inference for the return value of a function but there is no inference on the type of the parameters.This is important, we should always specify the type of the parameters of a function since typescript will never infer them.

  //arrow function + return type inference    const add = (a: number, b: number) => {        return a + b;    };
    //arrow function    const subtract = (a: number, b: number): number => {        return a - b;    };
    //native function    function divide(a: number, b: number): number {        return a / b;    }
    //anonymous function    const multiply = function(a: number, b: number): number {        return a * b;    };
    //void return type    const logger = (message: string): void => {        console.log(message);    };

    const todaysWeather = {        date: new Date(),        weather: 'sunny'    };
    //function and ES2015 destructuring    const logWeather = ({        date,        weather        }: {            date: Date;            weather: string;        }): void => {        console.log(date);        console.log(weather);    };
    logWeather(todaysWeather);

Annotations around objects

 const profile = {        name: 'alex',        age: 20,        coords: {            lat: 0,            lng: 15        },        setAge(age: number): void {            this.age = age;        }    };
    const { age, name }: { age: number; name: string } = profile;    const {    coords: { lat, lng }    }: { coords: { lat: number; lng: number } } = profile;

Annotations around arrays With typed arrays, each element is some consistent type of value.

 const carMakers = ['ford', 'toyota', 'chevy'];    const carMakers2: string[] = [];
    const dates = [new Date(), new Date()];    const dates2:Date[] = [];
    //2D Array    const carsByMake: string[][] = [];    -> an array that contains arrays of string

Why typed arrays ?Advantages:Help with inference when extracting values

const car = carMakers[0];    const myCar = carMakers.pop();
Prevent incompatible values
 carMakers.push(100);
Help with 'map', 'forEach', 'reduce', etc...
carMakers.map(    (car: string): string => {        return car.toUpperCase();    }    );
Flexible types
const importantDates: (Date | string)[] = [];    importantDates.push('2030-10-10');    importantDates.push(new Date());
When to use typed arrays: collection of records

Tuples

array like structure where each element represents some property of a recordEx: object reprsenting a drinkcolor -> browncarbonated -> truesugar -> 40['brown', true, 40]lost of the labels, the order is critical

 const pepsi = ['brown', true, 40];
According to type inference we have an array of string or boolean or number and are swappable
pepsi[0] = 40    pepsi[2] = 'brown'
Ok for typescript but we lost information since order is not respected anymore
  //tuple syntax    const pepsi: [string, boolean, number] = ['brown', true, 40];    pepsi[0] = 40 //err msg    pepsi[2] = 'brown' //err msg
We can use type alias
 type Drink = [string, boolean, number];    const pepsi: Drink = ['brown', true, 40];

Interface

create a new type, describe the new property
    const oldCivic = {        name: 'civic',        year: 2000,        broken:true    }
    const printVehicle = (vehicule: {name: string;year:number;broken:true}):void => {        console.log(`Name: ${vehicule.name`);        console.log(`Year: ${vehicule.year`);        console.log(`Broken: ${vehicule.broken`);    }
    printVehicle(oldCivic);
{name: string;year:number;broken:true} is long and is going to be dupplicated a lot.
    interface Vehicule {        name: string;        year:number;        broken:boolean;    }    const printVehicle = (vehicule: Vehicule):void => {    }
Functions in interface
interface Vehicule {        name: string;        year:number;        broken:boolean;        summary(): string;    }
    const oldCivic = {        name: 'civic',        year: 2000,        broken:true        summary(): string {            return `Name: ${this.name}`;        }    }
    const printVehicle = (vehicule: Vehicule):void => {        console.log(vehicule.summary());    }
    printVehicle(oldCivic);
General strategy for reusable code in TS is to create functions that accept arguments that are typed with interfaces. Object/classes can decide to implement a given interface to work with a function

Classes

   class Vehicule {        power: integer;
        constructor(power:integer) {            this.power = power;        }    }
    //is equivalent to    class Vehicule {        constructor(public power:integer) {}    
}

Generics

class ArrayOfAnything<T> {        constructor(public collection:T[]){}        get(index:number):T{            return this.collection[index]        }    }
Type inference:
const array = new ArrayOfAnything<string>(['a', 'b', 'c'])    const array2 = new ArrayOfAnything(['a', 'b', 'c']) //same as before, type inference is working

Generics with function

function printAnyThing<T>(arr: T[]):void {
    }
    printAnyThing<string>(['a', 'b', 'c'])    printAnyThing(['a', 'b', 'c']) //same as before, type inference is working

Generics constraints

 class Rectange {        print() {            console.log("I'm a rectangle")        }    }
    class Circle {        print() {            console.log("I'm a circle")        }    }
    //No garantee T will have a print method    function printShape<T>(arr:T[]):void {        for(let i=0; i<arr.length; i++) {            arr[i].print(); //nope!        }    }
    interface Printable {        print: void;    }
    //Ok now    function printShape<T extends Printable>(arr:T[]):void {        for(let i=0; i<arr.length; i++) {            arr[i].print(); //nope!        }    }

Advanced generics constraints

The goal is to avoid situation like that where data is an object with some values of type string, number and boolean: g

et(key: string): string | number | boolean {        return this.data[key];    }
Solution is:
get<K extends keyof T>(key: K): T[K] {        return this.data[key]    }

Type definition files

When using a js library typescript may complain it does not find a type definition file.The project DefinitelyTyped usually helps to find the missing file. search for @types<name of the module> on npm If we want to use a nodejs library like fs for example, we also need to install manually a definition type file for it. But in the case ofnodejs library we won't install @types/fs but @types/node. In case we are importing librairies directly in the html file, we need to make typescript understandthere is global variables.

//import google maps in htmlscript src="https://maps.googleapis.com/maps/api/js?key=...."></script>//now google global variable is available
To tell typescript what is going on we install a type definition file for google map
 npm install @types/googlemaps

Configuring the ts compiler

  tsc --init

tsconfig.json is generated. We can edit it configure the compiler. For examplewe can specify all ts files are in src and all compiled files must go in build directory

 {        "compilerOptions": {        ...        "outDir": "./build" /* Redirect output structure to the directory. */,        "rootDir": "./src" /*        ...        }    }
Concurrent compilation and execution. The ts files need to be automatically recompiled whenever there is a change and the compiled file must be automatically runned againt node.
npm install nodemon concurrently    //in package.json add 3 scripts:    "start:build": "tsc -w",    "start:run": "nodemon build/index.js",    "start": "concurrently npm:start:*"