Learning TypeScript - Part 0

09.08.2021

Motivation for TypeScript

Now after looking at JavaScript and programming a bunch of things you are slowly starting to get a feeling what programming is all about. It's about using functions to transform different types of values (numbers, strings, objects, etc.) into useful results which you can then use to compose your application. You probably also felt some frustration because often it did not work for non-obvious reasons. Maybe value was not what you expected or the function (or method) you tried to call did not exist. You aren't the only person who had frustration with these kinds of problems and there is a solution to this. Some programming languages use a compiler that checks your program before you even run it. But let's look at a bit of context first.

What is a programming language anyways?

You've been programming for a while now, but until now we haven't really talked about what a programming language actually is. Programming languages are made for humans (even though they may sometimes seem weirdly complicated): The hardware in your computer can't do anything with the code you type. It only understands 1s and 0s.

To actually run what you type, you have some intermediate program that translates your code to a machine language that your CPU (Central Processing Unit) can understand. In JavaScript that translator is part of the browser and runs just before your code is executed.

Machine language is quite complicated and verbose. For instance to add two numbers, you would have to read a piece of data from an address in your RAM into a so-called register, then you would have to read the second number into another register and then call a command that adds the two. Variables are a construct that we use, to make it easier for us to understand what we are doing but in reality its just memory locations and registers. If you are interested I'll write another post on how computers and programming languages work on the lowest level.

At some point, people were fed up with writing basically numbers that could be interpreted by computers and wrote so-called compilers to translate text that made a bit more sense to them into machine code. That was in the 1950s. Two programming languages called COBOL and FORTRAN are still in use today. The former by some poor sobs (though not in any financial sense) in the banking system who have to maintain decade old programs run as part of the critical infrastructure of banks, the latter is sometimes used in high performance computing for simulations for example. It runs on computers that are bigger than most houses.

Dynamically vs Statically Typed Programming Languages

Since the inception of programming languages bunch of things happened, people played around with different concepts, invented thousands of programming languages, learned a bunch of stuff and got various opinions on what makes a programming language productive. Some concepts are the same for every programming language: Almost all programming languages have functions and some way or another to represent numbers, strings and arrays and objects of sorts. Some other aspects vary wildly between languages.

One of those key differences are dynamically typed vs statically typed programming languages which, as if I had planned it, is also the key distinction between JavaScript and TypeScript.

When you put a number into a variable in JavaScript, and later you overwrite its contents with a string, the browser won't complain and happily continue executing your program. Likewise, you can pass any type of value to a function, and it will only fail, when you run it, and you get completely nonsensical values. How useful could it be if you could say: This function only works if the first argument you pass is a number or a string. Such a programming language in which you have to decide what types your arguments and variables have is called a statically typed programming language.

Introduction to TypeScript

For the Web browser, TypeScript is by far the most widely used statically typed programming language, and the best part about it: It's compatible with JavaScript. All type information is optional (but recommended).

But how does it work in practice? Can you just include any programming language and your browser will just understand it? Unfortunately no. You have to translate your code first into JavaScript. This is done by a program called compiler. As a bonus, the same program also checks if your program is syntactically correct and if the types match.

Let's have a look at the JavaScript example first:


// This function logs the first argument as many times as you want.
// Very useful to make your messages as obnoxious as you want
function logNTimes(message, n) {
    for(let counter = 0; counter < n; counter++) {
        console.log(message)
    }
}

// ...

logNTimes("Are we there yet?", 5)

The above example would print "Are we there yet?" five times. But what happens if we get confused and accidentally try to do the following:

logNTimes("Are we there yet?", "No!", 5)

These kinds of errors happen in reality. Especially in large projects. Maybe we didn't look at the original function which might be in a different file or we got confused.

If you want, you can try it out in you browser. Spoiler: It won't do a thing. Not even an error message or a warning. Apparently according to JavaScript 0 is not smaller than "No!" and so the loop will never run. Suddenly you have a bug in your code, and you might not even notice or wonder why you never see a message. Now you have to debug your stupid program. Let's do the same thing again in TypeScript.

But first we have to install it.

First, create a new project folder, so we don't mess with our previous exercises. Next, open a terminal in your project folder (or directly in VSCode if your project is already opened) and run the command npm install typescript. This will install the TypeScript compiler in your project folder.

No paste the same JavaScript code again into a new file called "hello.ts". (Notice the different file ending)


// This function logs the first argument as many times as you want.
// Very useful to make your messages as obnoxious as you want
function logNTimes(message, n) {
    for(let counter = 0; counter < n; counter++) {
        console.log(message)
    }
}

Now you can run the command npx tsc hello.ts. This will create a new file in the same folder called "hello.js" which will have almost exactly the same content. I can only assume how amazed you are by now. But even though the result might seem benign, we did something amazing. We wrote some code in TypeScript and used the compiler to translate it to JavaScript.

Before we continue, if you are using VS Code, you will probably see an error now, telling you, that you have a duplicate function definition. This can be fixed by creating a TypeScript configuration. Simply run the command npx tsc --init. This will create a new file called tsconfig.json which contains configurations on what checks the compiler will perform and which files will get translated. By default, it is very strict and won't allow you to not specify the types of arguments. You can change that by changing the line "strict": true to "strict": false.

Now that this is out of the way, we can try again what happens if we introduce the same error that got silently ignored in JavaScript:

function logNTimes(message, n) {
    for(let counter = 0; counter < n; counter++) {
        console.log(message)
    }
}

logNTimes("Are we there yet?", "No!", 5)

If you are using VS Code or any other IDE, it will probably already warn you, but let's run npx tsc hello.ts anyways: Most likely you will see the following:

hello.ts:7:39 - error TS2554: Expected 2 arguments, but got 3.

7 logNTimes("Are we there yet?", "No!", 5)
                                        ~


Found 1 error.

Immediately it tells you, that what you are doing doesn't make any sense. You try to pass three arguments instead of two and that doesn't make any sense. But our protection isn't perfect yet. Let's try to log "banana" times.

logNTimes("Are we there yet?", "Banana")

Running the compiler will work without any problems. Try it for yourself npx tsc hello.ts. Running the program will silently fail, and you didn't win a thing. To verify that you aren't passing any bullshit, you have to give type information in the original function definition.

function logNTimes(message: string, n: number) {
    for(let counter = 0; counter < n; counter++) {
        console.log(message)
    }
}

logNTimes("Are we there yet?", "Banana")

Suddenly you will see an error when running npx tsc hello.ts.

hello.ts:8:32 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

8 logNTimes("Are we there yet?", "Banana")
                                 ~~~~~~~~


Found 1 error.

Isn't this amazing? You will never have syntax or type errors again!

Exercise 0

Now that we know how TypeScript works we can re-enable the strict mode. Go to your tsconfig.json and change the line back to "strict": true.

This will disallow amongst other things to define functions that don't specify the type of their arguments. Now you can start programming TypeScript like a pro.

From your previous exercise, copy your solution to your new TypeScript project folder. Change the file ending from .js to .ts. Your job is to add type information to all of your functions.

Hints

In TypeScript, it is also possible to define your own types. We will leave that for a later exercise. For now set all of your object arguments to "any". Another thing to keep in mind is that when you pass arrays, you will need to say, what type the array contains. Do this by writing the type like this: Array<number> for an array of numbers for example.

Bonus Points

You can also specify the return type of functions in JavaScript. This is done like this.

function returnsANumber(): number {
    return 5
}

Find out the different return types of your functions and specify them explicitly.

Epilogue

I can only give you so much information about TypeScript. If you get stuck or want to know more about all the things that are possible with TypeScript, you can head over to their Website.

Some of the stuff we will cover in the next few blogs.