Skip to main content

Using TypeScript with Node.js and Express

 Ease of development is great when you are building a server written in JavaScript using Node.js and Express. What happens when this application server scales or you are working in a team of developers all across the world? TypeScript can help.

In this post, I am not going to talk about whether you should use TypeScript or not. This post describes a beginner-friendly way to set up TypeScript in an Express.js app and understand the basic constraints that come with it.

Prerequisites

To take full advantage of this tutorial, please make sure you have the following installed in your local development environment:

  • Node.js version >= 12.x.x installed
  • Access to one package manager such as npm or yarn
  • Basic knowledge of Node.js and Express

Create a minimal server with Express

Start by creating a new directory where you keep your side projects in your local development environment. Inside that directory, use npm’s initializer command to create a package.json file:

media server
cd server/
npm init --yes

The --yes flag uses the default settings when initializing a package.json from npm config you might have set up.

The package.json file created might look something like this:

{
  "name": "express-ts-example",
  "version": "0.0.1",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Aman Mittal (https://amanhimself.dev)",
  "license": "MIT"
}

After the initializing step, let us add an express package. From the terminal window, run the command:

yarn add express@4.17.1

Next, create a new file called index.js at the root of the project with the following code to trigger a minimal server:

const express = require('express');
const app = express();
const PORT = 8000;
app.get('/', (req,res) => res.send('Express + TypeScript Server'));
app.listen(PORT, () => {
  console.log(`⚡️[server]: Server is running at https://localhost:${PORT}`);
});

Go back to the terminal and trigger the common node index.js to start the server.

localhost displaying Express + TypeScript server

The Express server is now up and running.

Add TypeScript

Let’s add two libraries to the development server as devDependencies.

  • typescript is a core library that helps to compile the TypeScript code to valid JavaScript
  • ts-node is a utility library that helps to run a development server written using TypeScript directly from the terminal

To install them, from a terminal window run the following command:

yarn add -D typescript ts-node

The -D flag is also known as --dev flag and is a specification for the package manager to install these libraries as devDependencies.

Once these libraries are installed, go to the package.json file and see a new devDependencies object:

"devDependencies": {
  "ts-node": "8.10.2",
  "typescript": "3.9.5"
}

Next, create a tsconfig.json file at the root of the development server project. This file allows you to customize TypeScript configuration and add other configurations to compile the TypeScript project:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "rootDir": "./",
    "outDir": "./build",
    "esModuleInterop": true,
    "strict": true
  }
}

The compilerOptions is a mandatory field that needs to be specified. The options used in the config above are:

  • target allows us to specify the target JavaScript version that compiler will output
  • module allows us to use a module manager in the compiled JavaScript code. The commonjs is supported and is a standard in Node.js
  • rootDir is an option that specifies where the TypeScript files are located inside the Node.js project
  • outDir specifies where the output of the compiled is going to be located
  • esModuleInterop allows us to compile ES6 modules to commonjs modules
  • strict is an option that enables strict type-checking options

There might be other configuration options that you can add on for the TypeScript compiler but these are the basic configuration options specified that can help you to get started.

Install declaration files for Node.js and Express

Declaration files are predefined modules that describe the shape of JavaScript values (the types present) for the TypeScript compiler. Type declarations are usually contained in files with a .d.ts extension. These declaration files are available for all libraries that are originally written in JavaScript and not TypeScript.

There is a GitHub repository that maintains the TypeScript type definitions to use directly in Node.js and other JavaScript projects without bothering to define these types from scratch. This repository is called DefinitelyTyped.

To add these types or the declaration files related to a particular library or a module, you have to look for the packages that start with @types namespace.

For example, the type definitions for Express library is kept under a specific package called @types/express. For using a utility library such as bodyParser (which is a middleware to parse an incoming request’s body), there is a specific type of definition module called @types/body-parser.

To install type definitions for Node.js and Express, run the below command. Do note that, these type definitions are installed as devDependencie:

yarn add -D @types/node @types/express

Notice the versions of these packages installed in package.json file:

"devDependencies": {
    "@types/express": "4.17.6",
    "@types/node": "14.0.13",
    "ts-node": "8.10.2",
    "typescript": "3.9.5"
}

Create an Express server with .ts extension

Now you can easily convert the minimal server code in index.js to index.ts file. That is the first step. Rename the file to index.ts.

The .ts extension is a file extension to determine the TypeScript files that are compiled to JavaScript files later when building the server.

Open index.ts file. You can now use the import statements from ES6. The only required package right now in the index.ts file is express. Replace it with the following statement:

import express from 'express';
// rest of the code remains same
const app = express();
const PORT = 8000;
app.get('/', (req, res) => res.send('Express + TypeScript Server'));
app.listen(PORT, () => {
  console.log(`⚡️[server]: Server is running at https://localhost:${PORT}`);
});

The TypeScript compiler will handle the conversion of import statements to require statements.

Watching file changes with nodemon

Another development related utility library I like to use when working on Node.js projects is nodemon. Let’s install this using the command below:

yarn add -D nodemon

nodemon is a tool that helps develop Node.js based applications by automatically restarting the Node application when file changes in the directory are detected. To use it, you may add a start script in the package.json file as specified below:

"scripts": {
    "start": "nodemon index.ts",
},

Now, go back to the terminal window, and run yarn start or npm start.

nodemon index

Since there are no errors, the server is successfully running. You can go to the browser window to see the result.

Since nodemon detected changes, let’s try to edit the message sent from res.send() and simultaneously take a look at the terminal to see if nodemon detects any file changes or not.

using nodemon to detect changes in the file

The ts-node utility checks for any file changes in the current TypeScript project. If there is a TypeScript error, this module will let the nodemon crash the server and instead display that error.

Compile a TypeScript project

To compile a TypeScript project to a valid JavaScript one, start by declaring a new script called build inside the package.json file:

"scripts": {
    "build": "tsc --project ./",
},

TypeScript provides a command to compile the code called tsc. This command demands a flag to specify as to what to compile. The --project (shorthand: -p) is used to specify the project directory that the compiler can pick the code files from to compile to valid JavaScript. The ./ specifies the root project.

From the terminal window, run the build command to compile the code:

yarn run build

expresstsexample

There is a new build directory created after this command executes successfully. Inside this directory, there is the TypeScript code compiled to valid JavaScript:

'use strict';
var __importDefault =
  (this && this.__importDefault) ||
  function(mod) {
    return mod && mod.__esModule ? mod : { default: mod };
  };
Object.defineProperty(exports, '__esModule', { value: true });
const express_1 = __importDefault(require('express'));
const app = express_1.default();
const PORT = 8000;
app.get('/', (req, res) =>
  res.send('Express + TypeScript Server is awesome!!!')
);
app.listen(PORT, () => {
  console.log(`⚡️[server]: Server is running at https://localhost:${PORT}`);
});

If you specify any other directory named as the value of the property outDir in the tsconfig.json file that name of the directory would have reflected here instead of build.

Conclusion

Using TypeScript has its benefits but it does come with a bit of a learning curve. You have to carefully analyze whether using TypeScript in your Node.js and Express.js backend projects is beneficial or not. This may depend on the requirements you have. Make sure to check out the different Typed Definitions or go to the official TypeScript documentation to explore more.


Comments

Popular posts from this blog

How to use Ngx-Charts in Angular ?

Charts helps us to visualize large amount of data in an easy to understand and interactive way. This helps businesses to grow more by taking important decisions from the data. For example, e-commerce can have charts or reports for product sales, with various categories like product type, year, etc. In angular, we have various charting libraries to create charts.  Ngx-charts  is one of them. Check out the list of  best angular chart libraries .  In this article, we will see data visualization with ngx-charts and how to use ngx-charts in angular application ? We will see, How to install ngx-charts in angular ? Create a vertical bar chart Create a pie chart, advanced pie chart and pie chart grid Introduction ngx-charts  is an open-source and declarative charting framework for angular2+. It is maintained by  Swimlane . It is using Angular to render and animate the SVG elements with all of its binding and speed goodness and uses d3 for the excellent math functio...

Understand Angular’s forRoot and forChild

  forRoot   /   forChild   is a pattern for singleton services that most of us know from routing. Routing is actually the main use case for it and as it is not commonly used outside of it, I wouldn’t be surprised if most Angular developers haven’t given it a second thought. However, as the official Angular documentation puts it: “Understanding how  forRoot()  works to make sure a service is a singleton will inform your development at a deeper level.” So let’s go. Providers & Injectors Angular comes with a dependency injection (DI) mechanism. When a component depends on a service, you don’t manually create an instance of the service. You  inject  the service and the dependency injection system takes care of providing an instance. import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.compon...

How to solve Puppeteer TimeoutError: Navigation timeout of 30000 ms exceeded

During the automation of multiple tasks on my job and personal projects, i decided to move on  Puppeteer  instead of the old school PhantomJS. One of the most usual problems with pages that contain a lot of content, because of the ads, images etc. is the load time, an exception is thrown (specifically the TimeoutError) after a page takes more than 30000ms (30 seconds) to load totally. To solve this problem, you will have 2 options, either to increase this timeout in the configuration or remove it at all. Personally, i prefer to remove the limit as i know that the pages that i work with will end up loading someday. In this article, i'll explain you briefly 2 ways to bypass this limitation. A. Globally on the tab The option that i prefer, as i browse multiple pages in the same tab, is to remove the timeout limit on the tab that i use to browse. For example, to remove the limit you should add: await page . setDefaultNavigationTimeout ( 0 ) ;  COPY SNIPPET The setDefaultNav...