Taking Your Node.js Apps to the Next Level with Typescript

in Front-End Web Technologies

For a language developed in merely 10 days, JS has made a long way, evolving along time and gaining huge traction to become one of the most prominent programming languages today.

One of its great aspects is its dynamic nature, which allows users to do things like extending objects and definitions at runtime and changing types as we go along. However, this flexibility comes with a price tag – without type enforcement, there is no one watching our backs at dev/design time, and so potentially avoidable bugs easily slip into production to be caught only at runtime.

Luckily, TypeScript provides just what we need – strong typing in the form of the following features:

● Types
● Classes
● Interfaces
● Compile-time type checks

These features allow to better define the strong constructs and contracts (interfaces) that are enforced at dev/compile time, and ensure that (at least) some potential bugs are caught before runtime/production.

But not only that. TS code tends to be much more structured and better designed, and with eventual overall higher quality. It can therefore be deployed with more confidence.

(Side note: TS provides many more benefits, including future ECMAScript support, OO syntactic sugar, generics and a whole range of other cool features, but these are not in the scope for this article.)

Let’s Kick the Tires
We’re now going to setup our first Node.js with TS support, step by step. First, create a project folder, cd into it and run:

> npm init

This will create your initial version of package.json:

 "name": "node-ts",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1"
 "author": "zackyp",
 "license": "ISC"

Now install the typescript compiler (and check the installed version):

> npm install typescript -g
> tsc – – verion

Install typings (TypeScript definitions manager):

> npm install typings -g
> typings – – version

Typings is a tool that provides easy management of definition files (.d.ts), which are like “h” or “header” files for JS libraries. They provide declarations of APIs (libraries) written in JS, and allow to consume JS libraries from the TS code, providing strong types and intellisense capabilities in dev time.

Now that you have the basic tools in place, grab the Node’s definitions file:

> typings install dt~node -S -G

Note the prefixing dt~ which stands for Definitely Typed, a repository for TS definition files. The -S flag means “Persist to dependencies” (typings.json file), and -G means “Install and persist as a global definition”.

For the sake of practice, go ahead now and install underscore along with its typings:

> npm install underscore – – save
> typings install dt~underscore -S -G

If you take a look at the project structure now, you’ll see that a folder named typings was created, under which there is an index.d.ts file; and a global folder under which typings definitions go (like Node you’ve just installed). Also, a typings.json file was created, which contains a list of all typings you installed, very similar to the package.json file.

Inside the typings.index.d.ts file, you will see that the typings tool has added references to all definitions installed:

/// <reference path=”globals/node/index.d.ts” />

/// <reference path=”globals/underscore/index.d.ts” />

This allows to reference just this file in the code, so that type definitions will be available both in the development environment (intellisense features) and, more importantly, to the typescript compiler.

Now generate a typescript compiler options seed file:

> tsc – – init

You’ll notice a new file named tsconfig.json is created, containing compiler instructions such as the target ECMAScript version (default ES5), whether or not to generate map files (for debugging), strict level, etc. You can see the full list of available compiler options here.

You’re now ready to write your app’s code.
Create a reusable utils module (utils.ts):

* utils.ts

/// <reference path="typings/index.d.ts" />

"use strict";

class Utils {

   constructor() {

   public printCwd() {
       console.log(`cwd is: "${process.cwd()}"`);

export {Utils};

And the application’s main file (index.ts):

* index.ts

"use strict";

import {Utils} from "./utils";

var utils = new Utils();

Finally, update package.json to include the following npm scripts:

"scripts": {
 "compile": "echo 'building...' && typings install && tsc",
 "start": "node index.js"

Time to build and run the app.

Run the following commands:

> npm run compile
> npm start

Well done! You have just built, compiled and ran your first TS based nodejs app.

Executing TS Directly (without transpiling first)

Sometimes it’s convenient to run TS code directly without having to compile it first. There are several options to do this.

ts-node is a TypeScript execution environment and REPL for node. By installing it globally (npm install -g ts-node), and of course installing its prerequisite typescript compiler (npm install -g typescript), you can run the TS code directly.

For example:

> ts-node index.ts

When using PM2 in production, you also have the option to run TS code directly. All you need is to install the transpiler first:

> pm2 install typescript

And then run the TS scripts directly:

> pm2 run index.ts

For Good Measure

Needless to say, the TS app you just built is a bit naive, only intended to get you up and running with a basic setup.

In a real application, you’d probably want a more substantial ecosystem, including gulp automation, installing typescript and typings locally as devDependencies (and not globally as in this example). You’d also want compilation products outputted to a dedicated folder, and more.

To sum up: there is effort involved in setting up a node TS project vs. a simple JS based one. But the benefits are tremendous (intellisense, strong typing, using future ECMAScript features etc.).

Your turn – share your thoughts!

Contact us
You might also like