TypeScript vs ES6

Adding ES6/TypeScript Support to a NodeJS Server



·

In past tutorials, we have covered setting up a basic Node/Express server and even integrating a Node server with Ionic. Up until this point, we have just been using the standard ES5 JavaScript syntax when building the server.

If you are used to using Ionic, and many readers of this blog would be, then you may find using ES5 syntax a bit awkward. When we build Ionic applications we are able to use the ES6/TypeScript syntax, which provides a range of useful new JavaScript features as well as optional type checking.

In this tutorial, we are going to convert an existing Node/Express server to be able to use ES6/TypeScript syntax for development. Remember that TypeScript is a superset of JavasScript, meaning that all valid JavaScript is also valid TypeScript. TypeScript just adds additional features on top of the standard JavaScript syntax.

The reason that we need to use something like TypeScript in order to use newer JavaScript features like import, let, and const is that these features are not yet implemented in most browsers. The TypeScript transpiler will allow us to code using the latest features, but then it will transpile our code into the older JavaScript that browsers can understand.

Installing TypeScript

In order to use TypeScript, you will need to install the TypeScript package on your machine. In this example, we will be using the tsc command to run the TypeScript compiler, so we will need to install the typescript package globally:

npm install -g typescript

The -g flag used here means that the package will be installed globally, not just for this project. If you are using the same method in future projects, you will not need to install it again.

Setting up a Simple Example

We are going to use the example server from this tutorial and we are going to convert it to use TypeScript. You do not need to use this example, you can use your own code if you like, but if you do want to follow along with this code you can create the following files in a new project:

server.js

var express = require('express');
var bodyParser = require('body-parser');
var logger = require('morgan');
var methodOverride = require('method-override')
var cors = require('cors');

var app = express();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(cors());

app.listen(process.env.PORT || 8080);

package.json

{
  "name": "app-name",
  "version": "0.1.0",
  "description": "My Description",
  "engines": {
    "node": "6.11.1"
  },
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "body-parser": "^1.15.2",
    "cors": "^2.8.0",
    "del": "2.2.0",
    "express": "^4.14.0",
    "http": "0.0.0",
    "method-override": "^2.3.6",
    "morgan": "^1.7.0",
  }
}

You will also need to make sure to run the npm install command to install the dependencies.

Converting the Project

Now that we have a simple example to work with, we need to “convert” it to set up TypeScript. As I mentioned before, valid JavaScript is valid TypeScript, so there isn’t much we need to do. In fact, all you need to do is change the .js extension to .ts.

Rename server.js to server.ts

We are also going to add some ES6 syntax so that we can see what is going on when the transpilation happens.

Modify server.ts to reflect the following:

var express = require('express');
var bodyParser = require('body-parser');
var logger = require('morgan');
var methodOverride = require('method-override')
var cors = require('cors');

var app = express();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(cors());

let bigRedDog = 'Clifford';

app.listen(process.env.PORT || 8080);

All we’ve done is add the following variable:

let bigRedDog = 'Clifford';

However, we are using the ES6 specific let keyword. Now if we want to transpile this code, all we need to do is run the following command:

tsc server.ts

This will create a new file called server.js – you will have both a server.ts and server.js file now. The .js file is the one you would actually use to run your server, and if you take a look at it, you should notice that the let keyword is converted to var:

var bigRedDog = 'Clifford';

Our ES6 code has been converted back to ES5 code that will work everywhere.

Creating a TypeScript Configuration File

You could use the approach outlined above to develop with TypeScript/ES6, but it would be quite awkward and messy as your project grows. Instead, we are going to use the same method that a normal Ionic application uses and create a tsconfig.json file. This allows us to tell the TypeScript compiler how we want it to behave.

Let’s take a look at the tsconfig.json file from an Ionic application:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [
      "dom",
      "es2015"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "sourceMap": true,
    "target": "es5",
    "typeRoots": [
      "../node_modules/@types"
    ]
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "src/**/*.spec.ts",
    "src/**/__tests__/*.ts"
  ],
  "compileOnSave": false,
  "atom": {
    "rewriteTsconfig": false
  }
}

We are going to create a config file that, more or less, looks the same – ours will be a bit simpler, though.

Create a file called tsconfig.json at the root of your project and add the following:

{
  "compilerOptions": {
    "module": "commonjs",
    "removeComments": true,
    "sourceMap": true,
    "target": "es5",
    "outDir": "build"
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

This tells the compiler that we want to convert our code to es5 and that the new code should be output to a folder called build. The include property specifies where the compiler should look for TypeScript files – in this case, we want it to look for files anywhere inside of the src folder.

We are going to take an approach similar to Ionic in having a src folder that contains all of our development code, and a build folder that contains the final output. The compiler will create the build folder for us, but we will need to create the src folder and move our code there.

Create a folder called src

Move any .ts files into the src folder

Delete any .js files that were created by the compiler in the previous steps

Now we can simply run the following command in the project directory:

tsc

This will find any TypeScript files in the src folder, convert them to valid ES5, and send the output to the build folder. The structure of your project should now look like this:

Project structure of NodeJS server using TypeScript

If you wanted to run your server now, you would simply run the .js file inside of the build folder:

node build/server.js

Installing Types

At this point you will likely get some errors like this:

src/server.ts(1,15): error TS2304: Cannot find name 'require'.
src/server.ts(2,18): error TS2304: Cannot find name 'require'.
src/server.ts(3,14): error TS2304: Cannot find name 'require'.
src/server.ts(4,22): error TS2304: Cannot find name 'require'.
src/server.ts(5,12): error TS2304: Cannot find name 'require'.
src/server.ts(15,12): error TS2304: Cannot find name 'process'.

These won’t stop your application from compiling, but if we don’t give TypeScript the appropriate ‘types’ then it will complain. TypeScript doesn’t like to be kept in the dark.

If we wanted to use require then we would have to add the appropriate types for it. Since we have ES6 syntax available to us now, we don’t actually need to use require at all. Instead, we can just import any modules we want to use.

Modify server.ts to reflect the following:

import * as express from 'express';
import * as bodyParser from 'body-parser';
import * as logger from 'morgan';
import * as methodOverride from 'method-override'
import * as cors from 'cors';

const app = express();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(cors());

app.listen(process.env.PORT || 8080);

We are now importing all of our dependencies, but we are still going to run into problems with TypeScript. We will need to install the types for each of the packages that we are using. To do that, we just need to run the following command:

npm install --save-dev @types/express @types/body-parser @types/morgan @types/method-override @types/cors

Once you have done this, the application should compile without any complaints from TypeScript.

Summary

At this point, you will be able to use any ES6 feature you like, and you can also add types to your application. However, this process still requires the manual step of building with tsc which isn’t ideal. In a future tutorial, we will cover automating this so that the compiler does not need to be run manually (just like in an Ionic project).

What to watch next...