Learning TypeScript - Part 1

09.08.2021

Discussion of the Previous Exercise

During the previous exercise you added type information to your last JavaScript exercise. This probably felt new and strange to you. Even though we discussed the merits of having type information at length in the last article, the exercise itself may have felt a bit useless. I mean, the code was working already. Why change it now? These questions and feelings are all valid and in this exercise we will design our program from the start with TypeScript. But first let's set up the project.

Setup

Let's start a new project and this time we will do it like the pros from the terminal. For now, I am assuming that you are using either a Mac or Linux. If you want to do the same on Windows, I suggest you look into WSL (Windows Subsystem for Linux). It allows you to run a fully fledged Linux environment on a Windows PC.

Before we start, let's talk about what we are trying to achieve here. Up to now we always had a single file. For the JavaScript exercises we just linked it directly to our HTML file. When we switched to TypeScript, we had to call a compiler to translate our TypeScript to plain JavaScript. Now we are at the point where we want to create a larger project with multiple TypeScript files that depend on each other. Translating each one individually would be a really annoying mess. Also, including them each would make our lives miserable. Another challenge are our dependencies. Up to now we had exactly one dependency: the TypeScript compiler. But I'm going to let you in on a secret: most common problems have already been solved by someone and chances are high, that we will only have to install a library and use an existing solution.

All of this calls for a more robust setup. In the following steps I'll guide you through installing it locally.

Step 1 — Navigating with your terminal

The first step is o open a terminal or console. After you have done this, you will be greeted with a window and a blinking cursor. It may look a bit like this:

terminal

A terminal is basically a text interface from which you control your computer. You type commands followed by some arguments separated by spaces and then enter to launch a program. You can think of it a little like calling a function. Before you start, here is one piece of advice: if something in your terminal get's stuck or you are lost, simply press the Ctrl and c key at the same time. This will exit any running program.

One important concept you need to understand is, that in the terminal it matters where you are. The terminal is always pointing at a specific directory in your file system. You can find out which one that is by typing pwd (short for print working directory) and then hitting enter.

In my case this will just print the line /home/jan because that is my home folder. To show what this folder contains, simply enter ls (short for list) and a list of folders appears. You might see folders like "Desktop", "Downloads", "Documents" etc.

The folder we are interested in is called "Projects". If it does not exist yet (it wasn't shown after entering ls) you can easily create it with the command mkdir like this (don't type the dollar sign):

$ mkdir Projects

You can use ls again to verify, that the folder was correctly created.

Next we will navigate to the "Projects" directory with our terminal. Do this by typing cd Projects. To verify that it worked you can type pwd again. In my case it now shows /home/jan/Projects.

Now let's repeat the whole stick again. (Only type the lines with a leading dollar sign)

$ mkdir typescript1
$ ls
typescript1
$ cd typescript1

If you ever move to the wrong folder you can easily move one folder up again by typing cd ..

Step 2 — Installing Node

In the last project, we were already using NodeJS to run our typescript compiler. NodeJS is simply a way to run JavaScript outside your browser. It is mostly used for development tooling like our TypeScript compiler or to run a backend server. Those things aren't possible with your browser alone because by default it doesn't allow any website to access your local files or allow your computer to listen for incoming connections.

For this part of the tutorial we will need to make sure that we have at least version 12 of NodeJS.

To do so, run node -v to find out which version you are you using. If it doesn't start with v12 or higher you will have to run the following commands:

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
$ source ~/.bashrc
$ nvm install node

Now the latest version will be installed and used for all future projects.

Step 3 — Setting up our Project

This time, we want to set up a proper project. In the last tutorial, we were just using the compiler directly to translate individual files. This works perfectly fine for individual files, but it won't fly in larger projects where organization is key, and you don't want to mix your written TypeScript files with the generated JavaScript files.

On top of that it is cumbersome to always remember all the TypeScript options that you want to pass to the compiler. So to organize ourselves, we will create a npm package.

To do so, let's go back to our terminal and make sure that we are in the correct folder with pwd. For me, it shows /home/jan/Projects/typescript1.

Next let's get to the meat of it! Run npm init. It will ask you a bunch of questions. You can just hit enter a few times to initialize your project with the default values. After the command has run, the folder should contain the file package.json. If you want to see what's inside, you can use the command cat. Simply type cat package.json and the content of the file should appear in your terminal.

In our package.json file we need to do one last change. We need to open it with VS Code and remove the line "main": "index.js",. This option is meant for libraries that are reused in other projects. We are just developing a website, so we don't need it. If we were to include it, our dev tooling would throw errors later.

Step 4 — Installing the Dependencies

For now, we have created a project, but that doesn't help us at all with TypeScript or any of the reasons we wanted to create it in the first place. "Why did we even do this?" you might ask yourself. Well, with npm, we can manage our dependencies including TypeScript and even external libraries we want to install. Additionally, we can define so-called "scripts" in our package.json to have a shortcut for general tasks. It will get clearer in a few seconds.

For now lets install the TypeScript compiler like this npm install typescript --save-dev. You might wonder why we now pass the additional option --save-dev this time. Basically it means that npm should save in our package.json that you need this dependency whenever you are developing on your project. This is mostly useful when you want to work with git. Now you don't have to copy all the dependencies which might be a lot of data into your version control system (git) and upload it to the repository. Instead, you just upload the package.json and the newly created package-lock.json containing the exact version of your dependency. Next time, someone wants to install all the necessary dependencies all they have to do is navigate to the project folder in the terminal and run npm install. Now all the dependencies will be installed automatically.

Additionally, we will be using parcel to bundle all of our typescript code together. Please install it as well by entering npm insatll parcel --save-dev.

Step 5 — Setting up TypeScript

Now that the dependencies are installed, let's configure the TypeScript compiler. TypeScript has different levels of strictness. You can for instance disallow using the "any" type and force yourself and your hypothetical colleagues to always use proper types.

Additionally, you can configure which files to compile and where to put them, so you don't always have to specify that, when you run the compiler. Like last time, to create the configuration file, you have to run npx tsc --init in your project folder. This will create a file called tsconfig.json. The file has very reasonable defaults, so we will just leave it as is for now.

The only thing remaining is to create our first TypeScript file. First, we will create a folder called src. Let's use our newly acquired terminal skillz and do that by typing mkdir src. Next we create an empty file called index.ts in there. You can now start using VS Code for that (also possible from the command line by typing code .). If you wanna be fancy about it, you can even create the file from the console by typing touch src/index.ts.

Step 6 — Add HTML

Now the last step is really simple. Just copy the following code into a new file called index.html in the src folder:

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Learning JavaScript</title>

    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta name="description" content="" />
    <script src="index.ts" type="module"></script>
</head>

<body>
    <main id="content">
    </main>
</body>

</html>

Step 7 — Running the Project

Now we will use this strange parcel thing, that we installed in step 4. Parcel is a build tool, that does a lot of stuff for us. It will call the TypeScript compiler for all of our TypeScript files. It will translate our HTML file to include generated JavaScript instead of the TypeScript file. It will even analyze our source code and check which functions are never used and then not include them in the output and remove useless spaces and newlines from our HTML code, so that when we later host our website, people who visit it, will have to download less stuff.

Also, it simplifies our development process greatly by automatically reloading our webpage when we change something. This works by starting a web server on our computer with a permanent connection to our browser and telling it to reload, when our files change. To start this web server you have to enter npx parcel serve src/index.ts. You will now be able to access the website by typing the URL 127.0.0.1:1234 in your browser.

After all of this, we are finally done. This was a lot of work, but it is strictly necessary if you want to create larger projects. Your project folder should now have the following contents:

Leveling Up

After this monumental setup procedure, we are finally ready to create a larger project. But with great complexity comes great responsibility, meaning that we will have to organize our code. At some point code is just too large to keep the entire workings of it in our head. This means that we need to make sure that when we read our code, it's easy to understand what it does and also where to find it.

In the next few tutorials you will learn tools and concepts to help you separate your code into small, manageable and reusable units. You will learn about classes, modules and about some general best practices that help to keep them tidy, robust and logical. Along the way we will also have a look at how to use the TypeScript type system to help ensure the correctness of our code. If that doesn't excite you yet, just wait till you see how neat our code will look when applying these new concepts.

The Project

By popular demand, I have decided to make our next big project about web animations. Animations are perfect as an exercise, because they consist of small elements that are easily separated into classes. In addition to that it is fun, because we can immediately see the result of our progress, plus the bugs usually look hilarious.

In this first part of the exercise, we will keep it really simple. Painting square on a canvas. No moving things yet. Later we will expand on that and make the whole thing move.

Are you ready? Let's get started.

Exercise 1

Create a canvas element and draw a square on it. This is a tiny task but after this monumental setup procedure I think you deserve it.

Paste the following code in your index.ts file to get started:

function init() {
    // get content element
    // the exclamation mark means that we ignore the fact that document.getElementById might return null
    let content = document.getElementById('content')!
    // create the canvas element
    let canvas = document.createElement('canvas')
    // set the width to 800 pixels.
    canvas.setAttribute('width', '800');
    // set the hight of the element to 400 pixels
    canvas.setAttribute('height', '400');
    content.appendChild(canvas)
}

window.addEventListener('load', init)

The main difficulty of this exercise is to figure out how to draw squares or anything else on canvases. But with your googling skills and the MDN you will succeed, I'm sure.

Also, don't forget that you will now have to launch your project from the command line using parcel. Use the command npx parcel src/index.html to launch it.

Hints

If you get completely lost, it might help you to know that you first have to create the canvas element and then a drawing context for it with the method getContext('2d')