Typescript notes

Official Typescript site for downloads and documentation

Table of Contents

Installing and initializing a project

Typescript does “Static Checking”

npm install typescript
npx tsc

Then convert .ts to .js with tsc myfile.ts and run it with node cmyfile.js

Usual steps to start a common Typescript project in an empty folder

# To initialize a folder with Typescript (creates a `tsconfig.json` file)
tsc --init

# Create the `package.json` file.
npm init

# Create the usual folders (src for ts files and dist for js files)
mkdir src dist

# Create first ts file
touch ./src/index.ts

Then create a index.html file pointing to the compiled ./dist/index.js. Type ! in an empty index.html file and enter the script in the body:

<body>
    <script src="./dist/index.js"></script>
</body>

Useful commands

Run tsc in watch mode.

tsc --watch

Install the Live Server extension.

Variables

Javascript just has numbers (not int or floats for example)

let variablename: type = value
let text21 = "Hello World"; //This will detect its a string and make it type script. Not like in Javascript

// Adding this line makes the file a module instead of a script
export {}

In variables the type can be optional to enter if Typescript can guess it, but in functions I should normally always enter it

Functions

function name(num: number = 0) : boolean { //Function will return a boolean
    if (num > 0) {
        return true
    }
}

Or arrow function:

let loginUser = (name: string, email: string, isPaid: boolean = false): boolean => {
    return true
}

Its good practice to specifiy void if a function is meant to return anything, so no one tries to return something with it. We use never when the function trows an exception or terminates execution of the program For example:

function consoleError(errormessage: string): void {
    console.log(errormessage);
}

function handletError(errormessage: string): never {
    throw new Error(errmsg);
}

Functions that return an object

function createCourse():{}{
    return myobject;
}


function createCourse():{name: string, price: number}{
    return {name: "typescript", price: 1000};
}

type

type car = {
    readonly make: string; //mark this property as readonly
    model: string;
    year: number;
    color?: string; //mark this property as optional
}

//create a new type that extends car and adds a driver property
type carwithdriver = car & {
    driver: string;
}


function createCar(mycar: car):car {
    console.log(mycar.make + " " + mycar.model + " " + mycar.year);
    return mycar;
}

let carone : car = {
    make: "Volvo",
    model: "XC60",
    year: 2017
}

Arrays

const myarray: number[] = [1,2,3,4,5,6,7,8,9,10];
//Another format of doing the same is
const myarray2: Array<number> = [1,2,3,4,5,6,7,8,9,10];

//Double all numbers in myarray
const doubleArray = myarray.map((num) => {
    return num * 2;
});

//print out all numbers in myarray in same line
//and go to next line after printing all numbers
function printArray() {
    myarray.map((num) => {
        process.stdout.write(num + " ");
    });
    console.log();
}
printArray();

//Add 11 to the end ºof myarray
myarray.push(11);

//print out all numbers in myarray
printArray();

//array of arrys
const myimage: number[][] = [
    [255,255,255],
    [255,0,0],
];
export {}

Union

Union use case in variables

let badge: number | string = 100;
badge = "100 Club";

//Will only allow values of "gold", "silver" or "bronze"
let metal: "gold" | "silver" | "bronze" = "gold";

Union case with types

type User = {
    name: string;
    id: number;
}

type Admin = {
    username: string;
    id: number;
}

let alejandro: User | Admin = {name: "Alejandro", id: 1};
//I can change a property that was not defined in User but is in Admin
alejandro = {username: "alejandro", id: 1};

Union case with functions

function getId(id: number | string) {
    if(typeof id === "string") {
        return id.toUpperCase();
    }
    console.log('DB id is: ' + id);');
}

Union case with arrays

const myArrayWithNumbersOrStrings: (number | string)[] = [1,2,"text"];
const myArrayOfNumbersOrStrings: string[] | number[] = [1,2,3];
type MyArr = number[] | string[];

Tuples

Official definition: A tuple type is another sort of Array type that knows exactly how many elements it contains, and exactly which types it contains at specific positions

let position: [number, number] = [255,255];
type Person = [number, string];
let myPerson: Person = [1, "Alejandro"];
myPerson[0] = 2;

Enums

To define a set of named constants.

enum Manufacturer2 {
    Honda = 10, //You can optionally set the value of an enum
    Volvo,
    BMW
}

let myChoice2 = Manufacturer2.Volvo

console.log(myChoice); //This is output as 11.

Interfaces

Note: Key difference between interface and type is that interface can be re-opened to add new properties

interface Persona {
    readonly preId: number,
    email: string,
    Name: string,
    age?: number
    startProcess():string, //Can also be typed as: startProcess: () => string;
    getCoupon(name: string, value: number): number
}
//you can also extend interfaces
interface Persona {
    city?: string
}
interface SuperPersona extends Persona {
    superpower: string
}

let firstUser: Persona = {
    preId: 1,
    email: "hello@hello.com",
    Name: "John",
    startProcess() {
        console.log("Starting process");
        return new Date().toISOString(); //return current date in string format
    },
    getCoupon: (name: "Golden", value: 10) => {
        return 10;
    }
}

Classes, getters and setters

Getters and setters can be use to access private properties that are usually not available out of the class or to add a bit more logic when reading or writing the data.

class User {
    private counter: number = 0;
    protected key: string = "A1234" //can be accessed by child class
    constructor(
        private email: string,
        private name: string
    ) {}

    get getEmail(): string {
        return this.email;
    }

    get getcounter(): number {
        return this.counter;
    }

    set setcounter(value: number) {
        if (value < 0) {
            throw new Error("Counter must be greater than 0")
        }
        this.counter = value;
    }
}

const someone = new User("aa", "bb");

Class implementing an interface

A class can implement an interface to assure that it follows the same format

class myclass implements myinterface {
    constructor(
        public field1: string
        public field2: number
    ){}
}

Abstract class

You cannot create an object from an abstract class. We usually use them to extend them instead.

abstract class Car {
    constructor(
        protected model: string,
        protected year: number
    ) {}

    abstract getPrice(): void;
    getAgeInYears(): number
    {
        return new Date().getFullYear() - this.year;
    };

}

class Volvo extends Car {
    constructor(
        protected model: string,
        protected year: number,
        protected securitylevel: number
    ) {
        super(model, year); //super() is required to have all required values of the abstract class
    }

    getPrice(): void {
        console.log("Price is 10000");
    }
    getAgeInYears(): number {
        return super.getAgeInYears();
    }
}

Generics

//This function could for example get a Number and return a String
function example1(val:any):any {
    return val
}

//This function accepts multiple types but will always return the same type that was entered
function example2<Type>(val: Type): Type {
    return val
}
//Another more common way to write the same thing is using a letter (can be any letter or text, like 'T' or anything else):
function example3<T>(val: T): T {
    return val
}

I can also use generics to use a personalized type

function example3<T>(val: T): T {
    return val
}

interface Table {
    manufacturer: string,
    seats: number
}

example3<Table>({manufacturer: "Make1", seats: 4})