Typescript Notes

webdev
frontend
Author

Passawis

Published

December 12, 2018

Typescript

Typescript is a superset of Javascript, meaning that all Javascript are valid Typescript code. We can think of Typescript as giving Javascript types.

It is important to note that the code that you run at the end is actually Javascript, basically that Typescript generates Javascript that is ultimately run. So Typescript compiler is essentially a transpiler.

It is also important note that we mention that Typescript is a superset of Javascript the opposite is not true. Meaning that not all Typescript are Javascript program. So Typescript essentially can be thought of as typechecker, it helps you detect whether your Javascript code will throw an error at runtime. Note that this is not fail proof, meaning that code that actually passes the type checking of Typescript can still throw error at runtime.

Separation of Runtime

It is important to note that all type information once run through the tsc compiler that transpiles the Typescript code to Javascript that the type information is gone. Meaning that the types in the program will not affect your generated Javascript code that is generated from the tsc compiler and therefore you cannot use Typescript types at run time.

Structural Typing

One of the things I got confused when learning about Typescript is that it actually uses Structural Typing. Essentially this means that structure that looks the same will be compaitable as the same type.

interface Person {
       first_name: string
       last_name: string

}

interface PhoneContact {
       first_name: string
       last_name: string
       contact_no: number
}


function printFullName(person: Person) {
       console.log(person.first_name + " " + person.last_name)
}

You can all the function printFullName with PhoneContact since the required type Person of the parameter is compaitable with the PhoneContact as they both have a first_name and last_name of type primitive string. The code below is valid.

const eric: PhoneContact = {first_name: "Eric", "last_name": "Ma", "contact_no": 1234569}

printFullName(eric) // valid

Type Inference

In languages like C and Rust the types are static, meaning that the types do not change. This is not the correct way to think of types in Typescript, you can think of a type of a variable in Typescript as a current type at that specific point in code. You can then use control flow to refine the types this is also known as narrowing a type. Below is a basic example of you narrowing the type using a control flow if.

type Currency = "pounds" | "dollars";

function formatCurrency(amount: number, currency: Currency) {
    if (currency === "pounds") {
    // inside this block, currency has type of currency: "pounds"
        return `£${amount}`;
    } else {
    // currency is narrowed to currency: "dollars''
        return `$${amount}`;
    }
}

console.log(formatCurrency(100, "pounds"));  // Output: £100
console.log(formatCurrency(50, "dollars"));  // Output: $50

Another concrete example would be if you have a union of type string and number.

function processValue(value: string | number) {
    if (typeof value === "number") {
        // value: number
        console.log("Number:", value.toFixed(2));
    } else {
        // value: string
        console.log("String:", value.toLowerCase());
    }
}

Although the typeof is a runtime check the Typescript compiler understands that you have checked in the if branch that the type is number and in that block it narrows the type down to number. Since our value can only be type string | number the else branch deduces that the type of value in that branch can only be string