Introduction to TypeScript

This post is 4 years old. (Or older!) Code samples may not work, screenshots may be missing and links could be broken. Although some of the content may be relevant please take it with a pinch of salt.

TypeScript is language developed by Microsoft, and it's a superset of JavaScript. When we say 'superset', we mean that TypeScript has all the JavaScript features, but additionally, it extends the language with things like interfaces, generics and – one of the most exciting additions in my opinion – typings. In fact, we could be a bit more specific and state that TypeScript is a superset of ES2015 because a lot of features that are available in ES2015 (such as arrow functions) are also available in TypeScript.

Before we take a look at the basic behaviour of TypeScript we need to discuss a few key terms and processes that will help us out when creating applications using TypeScript.

Transpilation

Transpilation is a process of transforming an application from one language to another one (transpilation is sometimes also referred to as source-to-source compiling). For TypeScript, transpilation is essential as we need to transpile our TypeScript code to JavaScript so that browsers and other environments can execute it.

During this transpilation process, we can tell the transpiler how to create the final JavaScript code by feeding it some options.

tsc

tsc is a command line TypeScript compiler that has many options for transpilation – these options can be added either inline or via a tsconfig.json configuration file.

Since tsc is a command line tool, we need to install that. Luckily, it's something that we can do easily since tsc is available as an npm package when we install TypeScript. It also makes sense to install tsc as a global package so that we can use it in any project where TypeScript compilation is required.

npm i -g typescript
tsc -v

Let's try out and see how we can generate a JavaScript file from TypeScript. Create the following, rather basic, TypeScript file:

// app.ts
function greet(name: string): string {
return `Hello ${name}`;
}

There are some type annotations added here, this is a topic that we'll be discussing later.

To generate JavaScript code we need to execute tsc app.ts using the command line.

Without giving any parameters, this will yield a file with the same name as the input file but with a .js extension. If we open that file, we'll see that our code has been transformed to plain JavaScript. Actually, by default, it has been transpiled down to a really old version of JavaScript (ES3).

We can modify this behaviour by adding a flag to our tsc command: tsc --target es6 app.ts. This is now going to generate ES6 (ES2015) compatible code.

tsc comes with a lot of compile options, and even though we could specify these options via the command line, it'd make much more sense to keep them in a configuration file.

tsconfig.json

Loading compiler specific configuration is possible via tsconfig.json. We can immediately try this by adding the configuration file with the following content:

{
"compilerOptions": {
"target": "es6"
}
}

Running solely tsc app.ts now yields an ES6 (ES2015) compatible code. You can check the following page for other compiler options.

The resulting file – regardless whether the target was specified to be es3 or es6 is executable via Node.js which we can immediately test by typing in node app.js in the command line. (The same app.js file could also be inserted into an HTML page and used in the browser.)

Workflow

As I mentioned earlier, we need to transpile TypeScript code to JavaScript for browsers (and other environments, such as Node.js) to be able to execute it. There are some build tools available that can do this job for us and the one that we are going to be discussing is going to be webpack.

So, the question is of course why not use tsc, why do we need another tool? The answer is two-fold.

First, let's face it, it is improbable that we'll only ever need to transpile TypeScript code without having to do additional work for our site – think about things like concatenating CSS files for example. Webpack helps us to add extra steps to our build process.

Second, when we introduce modules in our TypeScript code, it won't only be enough to transpile one file, but we'll need to build somehow up a dependency of files that are required by the final JavaScript file. Webpack helps us with this as well.

Webpack

Webpack is a module bundler that is capable of creating a single bundle file from multiple sources by building up a dependency graph. This introduces a compelling concept which we can not only be utilised for TypeScript and JavaScript but also for HTML and CSS files as well. At its most basic level webpack requires you to specify the following three configuration items: entry, output, loader and optionally a plugin.

Webpack also uses a mechanism called tree shaking which eliminates the inclusion of unused export statements from the final bundle and therefore achieving optimisation (i.e. smaller bundle size). We'll learn more about this later.

To work with webpack, we need to make sure that it's installed – we can, of course, install it via npm: npm i -g webpack.

As mentioned earlier webpack will build a dependency graph and to build that we need an entry point – think of this as the main application file. For every entry-point specified we'll get an output bundle – this is going to be the generated JavaScript file that we'll be able to execute in the browser (or via Node.js). The third bit that webpack needs is the loader. Loaders enable webpack to process files – any file. A loader consists of a module which tests for files and applies transformations to them.

Webpack requires us to specify a configuration file – which by default has the name webpack.config.js. Let's take a look at how an example configuration would look like:

// webpack.config.js
module.exports = {
entry: './app.ts',
output: {
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.ts?$/,
loader: 'ts-loader',
},
],
},
};

We can translate the above to simple English: take the app.ts file as an entry to start building the dependency graph. For every file that has a .ts extension, run them through the ts-loader and bundle the result into a file called bundle.js.

We can then take bundle.js and run it in Node.js or even add it to the browser as it'll contain 100% valid, executable JavaScript code.

To be able to transpile TypeScript code we need to make sure that we run webpack from the command line, making sure that we call that command from the same place where we have placed webpack.config.js.

Before we take a look at an example, we also need to mention that the loaders need to be installed via npm as well – in our case we need to make sure that we call npm i ts-loader in the folder where we are currently setting up the examples.

Now that we have webpack and ts-loader installed let's give this a go and see how we can transpile our TypeScript code to JavaScript.

Create two TypeScript files with the following content:

// math.ts:
export class MathsModule {
sum(...numbers: number[]): number {
return numbers.reduce((acc, num) => acc + num);
}
}

// app.ts

import { MathsModule } from './math';

const math = new MathsModule();
console.log(math.sum(4, 5, 6));

This is a fundamental application – we are going to explore all the type annotations that you see here later on – where we have created a Maths module with a sum function that sums up all the numbers that are passed to it as arguments. In our 'main' application file (app.ts) we import the module and invoke the appropriate method.

Execute webpack from the command line, and once it has finished running, we should get a bundle.js file. (Bundle.js does contain a lot of webpack related code which is all required to make sure that the JavaScript code can be executed in the browser.)

Astute readers will notice that bundle.js has ES6 (ES2015) code generated. Webpack also makes use of the tsconfig.json file that we have created earlier.

Feel free to use Node.js and execute bundle.js:

$ node bundle.js
15

At the time of writing, there's limited support in browsers for understanding require statements. Even though we can generate JavaScript code using tsc that will create files using require() statements – those would only work using Node.js but not the browser. You can give this a go if you want by calling tsc app.ts and running node app.js. Notice math.js also got created. Now you could run browserify to create a browser specific bundle: browserify app.js -o web-bundle.js – assuming that you have browserify globally installed via npm. Webpack does all this for us in one go.