Typescript Cheatsheet

Posted on May 31, 2017 by Sidharth Mishra

Compilation and watch:

Compile typescript file to ECMAScript 5(ES5) or pre-JS2015 using the command below.

tsc <filename>.ts --target ES5

Watch all typescript files for changes:

Watch all the typescript file for changes and continually compile them into ES5 JavaScript files.

tsc *.ts --watch --target ES5

strict mode:

"using strict";

Variable declarations (i.e. var x;) are valid for the entire scope they are written in, even if you declare after you assign.

This is what is meant by hoisting. Because of hoisting, the variables that have been declared using the var keyword get moved to the top of function body.

// an example of hoisting
function f() {
  var k = 5;
  for(i = 0; i < 5; i ++);
  console.log("k=" + k + " i=" + i);  // prints k=5 i=5
  var i = 6;
  console.log("i=" + i);              // prints i=6
}

i was declared and defined on the last line of f() but used in the 2nd line. Because of hoisting the function became something like:

function f() {
  var i;                              // i declaration moved to top of function
                                      // because of "hoisting"
  var k = 5;
  for(i = 0; i < 5; i ++);
  console.log("k=" + k + " i=" + i);  // prints k=5 i=5
  i = 6;
  console.log("i=" + i);              // prints i=6
}

“Strict mode” does not change any of this.

It would throw an error if you omitted the var x; declaration altogether.

Without strict mode, the variable’s scope would implicitly be the global scope.

If you currently have foo = “bar” without defining foo first, your code will start failing.

let, const and var:

let declares in block scope. Valid only within a scope.

const defines constants. It is block scoped as well.

var declares with global scope. When used can modify global variables from any scope.

let x = 5;

function printMe() {
    console.log(x);   // TS will scream
                      // Block-scoped variable 'x' used before its declaration.
                      // The scream is because of the let x declaration
                      // on the line below.
                      // if that is removed, x will be `5` from the scope above
                      // the function, i.e global x in this case. 
                     
    let x = 7;
}

console.log(x);       // output: 5
                      // since the value of x in the scope being
                      // considered is 5

printMe();            // output: undefined
                      // because `x`, variable gets hoisted
                      // during execution.
                      // inside function printMe():
                      // let x;
                      // console.log(x);
                      // x = 7;
                      // the declaration of x is hoisted but not the definition of x.

var x = 8;

function printMe() {
    console.log(x);   // TS will not scream
                      // since var is used inside the function body block.
    var x = 7;
}

console.log(x);       // output: 8

printMe();            // output: undefined
                      // same case as above
            
            
// difference between let and var becomes apparent here
let x = 8;

if (x > 0) {
    
    let x = 4;
    console.log(x);                     // output: 4
                                        // let declares block scoped variables
}

console.log(x);                         // output: 8

var y = 9;

if (y > 0) {
    
    var y = 10;
    console.log("inside y = " + y);     // output: inside y = 10
}

console.log("outside y = " +y);         // output: outside y = 10

// the difference is apparent
// var is modifying the global variable
// but let is only giving blockscoped  context

Datatypes, identifier names etc:

  • Can begin with an alphabet[a-zA-Z], $ or _ followed by [a-zA-Z0-9$_].

  • The types are optional in typescript.

  • Can use typeof(identifier) to find the type of the identifier/variable.

let $dollar123 = "";
let myName:string = "Sidmishraw";
let myAge: number = 24;
let canVote: boolean = true;
let anything: any = "bulbasaur";
let pokemon = "charmander";

anything = 12;                // won't throw an error, since it is of any type
myAge = "twenty four";        // this will throw an error from the TS compiler.

Type conversions:

// converting from an integer string representation
let str2int: number = parseInt("5");

// converting from a floating point string representation
let str2float: number = parseFloat("5.66");

// getting string value
// calling the `toString()` on the number TS object
console.log(str2float.toString())

Note: The toString() will convert any datatype to a string.

Constants:

Using the const keyword, can declare constants. Same as ES6. The values cannot be changed anymore like constants.

const PI = 3.1416;
const __PIKA__ = "Pikachu";
const __BULBA__ = "Bulbasaur";

Interfaces (as complex types):

Used to create complex datatypes:

interface Pokemon {
    id: number;
    name: string;
    combatPower: number;
};

// Pokemon became a complex data type
// that needs to have the fields defined.
// Now, bulbasaur is a Pokemon so it needs to have all those
// three properties.

// BTW, any object having those three properties
// will qualify as a Pokemon.

// interfaces are similar to interfaces of golang
// they needn't be implemented explicitly, if an object
// satisfies their structure, it can be used wherever the interface is used.
let bulbasaur: Pokemon = {
  id: 1,
  name: "Bulbasaur",
  combatPower: 500
};

let charmander = {
    id: 4,
    name: "Charmander",
    combatPower: 512,
    weight: 12
};

function isPokemon(p: Pokemon) {
    console.log(`Yup, this guy is a pokemon and it's name is ${p.name}`);
}

isPokemon(bulbasaur);       // output: Yup, this guy is a pokemon and it's name is Bulbasaur

isPokemon(charmander);      // output: Yup, this guy is a pokemon and it's name is Charmander

Arrays:

Syntax is:

let <identifier>: <datatype>[] = <array>;

or

var <identifier>: <datatype>[] = <array>;
  • All features are same as in JS.

For eg:

let pokemons: string[] = ["bulbasaur", "charmander", "squirtle", "pikachu"];

pokemons.push(5); // will give an error
pokemons.push("aerodactyl");

let pokemons: Pokemon[] = [];
pokemons.push({
                id: 1,
                name: "Bulbasaur",
                combatPower: 500
              });

// Arrays still have the subscript
// notation to access the elements by index
console.log(pokemons[0].toString());              // will print:  [Object object]
console.log(JSON.stringify(pokemons[0]));         // will print:  {"id": 1, "name": "Bulbasaur", "combatPower": 500}

// tuples
let tuple: [string, number] = ["hey", 1];

console.log(tuple[0]);                            // output: hey
console.log(tuple[1]);                            // output: 1
console.log(tuple[3]);                            // undefined

tuple = [2, "string1"];                           // TS will scream, order is important!

Maths:

Javascript math is still valid in TS.

Note: eval() evaluates the string expression within it and returns the result.

eval("5 + 4");              // = 9
eval("5 - 4");              // = 1
eval("5 * 4");              // = 20
eval("5 / 4");              // = 1.25
eval("5 % 4");              // = 1
eval("5 + \"four\"");       // = 5four
  • ++ and -- behave the same as in JS, Java, C, C++ etc (post and pre styles).

Conditionals and Loops:

if, switch and for behave the same as in JS.

let x: number = 2;

if(x % 2 === 0) {
    console.log("even");
} else {

}

let randArray = [5,6,7,8];

// old for-in loop also called for each in java/c++11
// prints the indices of the array
// val = 0, 1, 2 ,3
for (let val in randArray) {
    console.log(val);
}

let strArray = randArray.map(String);
// same as
// let strArray = randArray.map((x)=>x.toString());

// for - of loop new in TS/ES6
// prints the values of the array
// instead of the indices
// val = "5", "6", "7", "8"
for (let val of strArray) {
    console.log(val);
}

Functions:

Same style as normal JS with some additional syntax:

function getSum(num1:number, num2:number): number {
    return num1 + num2;
}

// void return type can be left out
function printMe():void {
    console.log("Print")
}

let sum: number = getSum(5, 6);
let sum2 = getSum(10, 12);
let sum3 = getSum(10, "pika"); // TS screams here

// num2 has default value
// num3 has a `?` after it
// this syntax is used for cases when it is not clear
// if num3 will be having a value
let getDiff = function(num1:number, num2=0, num3?: number):number {
    if (typeof (num3) !== "undefined") {
        return num1-num2-num3;
    } else {
        return num1-num2;
    }
};

// varargs
// treats the variable args as an array
// same as in case of ES6/7
let sumAll = function(...nums: number[]):number {

    return nums.reduce((acc, x)=>acc + x, 0); 
};

console.log(sumAll(1,2,3,4,5,6,7,8,9,10));


// lambdas or arrow functions
// same as ES6/7
var addOne = (x:number) => x + 1;

Class:

class Animal {
    
    // public attribute
    public favFood: string;
    
    // careful with naming of private variables
    // and their getters/setters
    private _me: string;
    
    private static numOfAnimals: number = 0;
    
    // can use the private/public 
    constructor(private name:string, private owner:string, me:string) {
        
        Animal.numOfAnimals ++;
        this._me = me;
    }
    
    ownerInfo() {
        console.log(this._me);
    }
    
    static howMany():number {
        return Animal.numOfAnimals;
    }
    
    // getter
    get me():string {
        
        return this._me;
    }
    
    // setter
    set me(me:string) {
        this._me = me;
    } 
}

let spot = new Animal("Spot", "Me", "Dog");

spot.ownerInfo();

Animal.howMany();

spot.me = "hey";

// Inheritance
class Dog extends Animal {
    
    constructor(name:string, owner:string) {
        super(name, owner, "Dog");
    }
}

// check inheritance
let d = new Dog("Gr", "Me");

console.log(d instanceof Dog);      // true
console.log(d instanceof Animal);   // true

// checking for fields
console.log("name" in d);           // true
                                    // doesn't matter if the variable is 
                                    // private or public

Interfaces in inheritance:

Interfaces act as contracts that need to implements by the classes.

interface Vehicle {
    move():void;
}

class Car implements Vehicle {
    move():void {
        
    }
}

class Bike implements Vehicle {
    move():void {
        
    }
}

Generics:

Similiar to generics in Java, C++ and C#

 // ---------- GENERIC FUNCTIONS ----------
 // We use generic functions when we want
 // to be able to work with multiple data
 // types in similar ways
  
 // To create a generic function we place
 // 1 or more data type markers in angled
 // brackets after the function name. We
 // then use those data type markers
 // instead of actual data types.
  
 function GetType<T>(val: T): string{
   return typeof(val);
 }
  
 let aStr = "A String";
 let aNum = 10;
  
 document.write(GetType(aStr) + "<br />");
 document.write(GetType(aNum) + "<br />");
  
 // You define a generic function that
 // excepts any class that implements
 // an interface
  
 function GetWheels<w extends Vehicle>(veh: w): number {
   return veh.drive();
 }
  
 GetWheels(car);
 GetWheels(bike);
  
 // You can also define generic classes that
 // can work with multiple data types
  
 class GenericNumber<T>{
  
   // An arrow function as described above
   add: (val1: T, val2: T) => T;
 }
  
 let aNumber = new GenericNumber<number>();
  
 // Define how we want add to work with numbers
 aNumber.add = function(x, y){return x + y;};
  
 document.write("5 + 4 = " + aNumber.add(5, 4) + "<br />");
  
 let aStrNum = new GenericNumber<string>();
  
 // Define how we want add to work with strings
 aStrNum.add = function(x, y){return String(Number(x) + Number(y));};
  
 document.write("5 + 6 = " + aStrNum.add("5", "6") + "<br />");
References: