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:
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).