Developing for Node.js with TypeScript instead of JavaScript – why and when you should switch.

For more details on setting up TypeScript projects see these step-by-step tutorials for Intellij IDEA / Webstorm and Visual Studio Code – free and Open source IDE

Code maintenance challenge

Node.js is a powerful runtime platform and JavaScript is a very popular language which minimises initial learning. This combination makes it extremely easy to put our ideas into code and get them running.

It goes well for as long as the code fits into a couple of screens. However, as our prototype evolves into a fully-functional service, new features being implemented. This leads to codebase expansion, potentially spreading your code among multiple modules / projects. At this point we hit a problem that is common for all dynamic languages – we no longer sure that the code is even runnable until we actually run it.

This problem can be addressed by certain level of test coverage – from unit tests to end-to-end tests. When applied properly, this approach gives us some confidence.

However, there is another problem that we shouldn’t forget – code maintainability. The more code we have – the harder it is to modify or extend. Faulty code change can be detected with the tests, but we still loose time for at least one extra modify-(deploy?)-test iteration. In languages like Java, compilation step and such IDEs’ features like code assist and refactoring support, make it really easy to identify (and get rid of) most errors as we type the code. It saves a lot of time.

When I started developing for Node.js and tried to get the most of my favourite IDE – IntelliJ IDEA, I found that it doesn’t really do much of code assist for JavaScript. I noticed that I started jumping between different areas of code just to look at function and class declarations when I wanted to use them. After some research I came across a project on GitHub – DefinitelyTyped. This project is a collection of interfaces for the most popular npm modules. The interfaces are defined in TypeScript and can be used in IntelliJ IDEA to improve code assist functionality. It worked perfectly for my JavaScript projects – IDEA allows mixing JavaScript and TypeScript in one project. As a next step, I started looking deeper into TypeScript and realised that it fixes the biggest flaw of JavaScript – lack of types! Instead of putting missing bits of information into comments or JSDoc annotations I was able to actually define interfaces both readable by people and used by compiler!

I started migrating my projects one by one to TypeScript which led to improvement in code quality and reusability. In this process I learned quite a few valuable lessons which I want to share with you.

TypeScript at a glance

The first thing you should know about TypeScript – it’s compilable to JavaScript. This means that while you edit TypeScript code, after compilation you end up with JavaScript code which can be executed by Node.js. Another thing, it’s a super-set of JavaScript, meaning that (almost) any JavaScript code is valid TypeScript code. On top of JavaScript features TypeScript offers optional type declaration for variables and arguments, interface declaration, some ES6 features (like lambdas, proper class declaration – without those pesky “prototype”-based model, export and import for modules) and more.

Migrating to TypeScript

I assume your code is big enough and you have at least few separate modules. For those modules that are mature and don’t change often would be wise to create TypeScript declaration file instead of rewriting it to TypeScript completely. A huge collection of such files is available in DefinitelyTyped that I mentioned earlier. For new modules or modules that you want to change any way it would make sense to rewrite them in TypeScript to benefit from new features.

As a part of this exercise I will prepare interface definition file for one of my libraries node-docker-monitor. It’s quite simple – just exports one function, so it won’t benefit much from TypeScript.

It is a convention to use .d.ts extension for TypeScript declaration files. These files don’t contain any implementation but rather describe modules implemented elsewhere. It’s important to keep declaration files in sync with the actual implementation otherwise they well do more harm than good. In this case we declare that our module exports only one function – MonitorFunction. That function accepts two parameters:

  • handler – a mandatory parameter of type EventHandler – an object that has two member functions declared – onContainerUp and onContainerDown
  • opts – an optional parameter of type DockerodeOptions or Dockerode

and so on.

Let’s create a simple JavaScript project based on node-docker-monitor and then convert it to TypeScript.

This service listens to Docker events and prints a Docker container info when it goes up or down. Find out more about Docker monitor.

Now let’s see what happens when we mistype one of the parameters.

JavaScript project - mistyped property is not detected

JavaScript project – mistyped property is not detected

Our IDE does nothing to indicate the problem.

Now, we will convert our project to TypeScript

and see how similar error is handled

TypeScript project - mistyped property is detected

TypeScript project – mistyped property is detected

but what happens if we remove one of the members completely

TypeScript project - missing property is detected

TypeScript project – missing property is detected

As you can see, with TypeScript, compiler is able to detect invalid argument usage and IDE highlights the problematic code (normally as you type it). Although given example is extremely simple and we would probably notice problem by just looking at the code, this principle obviously works in much bigger scale as well.

Apart from detecting errors, code assist works well too

TypeScript code assist in Intellij IDEA

TypeScript code assist in Intellij IDEA

For those who curious what compiled to JavaScript code would looks like

As you can see, the code is very clean and readable. In this particular example, it’s almost identical to our initial JavaScript code.

Not convinced? Here are just few more features that will improve your code.

String templating

Enums

Interfaces

Classes

Functions – optional parameters

Functions – default parameters

Functions – rest parameters

There are heaps more to discover on TypeScript official site.

In this post my intention was to demonstrate how you can benefit from moving your Node.js projects from JavaScript to TypeScript.

If you want me to write a detailed step-by-step tutorial for setting up basic TypeScript project (it can be a bit tricky), please leave a comment below.

As promised, here is a step-by-step tutorial for setting up TypeScript and Node.js project in Intellij IDEA

and as a bonus, another tutorial for setting up TypeScript project in Visual Studio Code – Free and Open source IDE

 

Share This

Share This

Share this post with your friends!