TypeScript in Node.js

Chapter Outline

TypeScript in Node.js: Writing Your First TypeScript Node Application

Node.js has become a cornerstone of backend development, thanks to its efficiency and the massive ecosystem of packages available through npm. Combining Node.js with TypeScript can enhance your development experience by providing strong typing and the latest ECMAScript features. This guide will walk you through setting up and writing your first TypeScript application in Node.js.

Prerequisites

Before you start, make sure you have the following installed:

  • Node.js (download from nodejs.org)
  • npm (comes installed with Node.js)
  • A text editor or IDE that supports TypeScript (like Visual Studio Code)

Setting Up Your Project

Create a new directory for your project and navigate into it

bash
mkdir my-typescript-app
cd my-typescript-app

Initialize a new npm project

bash
npm init -y

This creates a package.json file which manages your project dependencies and scripts.

Install TypeScript and Node.js types

bash
npm install --save-dev typescript @types/node

typescript is the TypeScript compiler, and @types/node provides TypeScript definitions for Node.js, which will help with autocompletion and type checking.

Create a tsconfig.json file

This file configures the options for the TypeScript compiler. Create tsconfig.json in the root of your project and add the following configuration:

tsconfig.json
1{
2 "compilerOptions": {
3 "module": "commonjs",
4 "esModuleInterop": true,
5 "target": "es6",
6 "moduleResolution": "node",
7 "sourceMap": true,
8 "outDir": "dist"
9 },
10 "include": ["src/**/*"]
11}
  • "module": "commonjs": Use CommonJS modules, the standard in Node.js.
  • "esModuleInterop": true: Enables compatibility with non-ESModule packages.
  • "target": "es6": Compile to ES6.
  • "outDir": "dist": Store compiled JavaScript files in the dist directory.
  • "include": ["src/**/*"]: Include all files in the src directory for compilation.

Set up your project structure

Create a src directory where your TypeScript (*.ts) files will live:

bash
mkdir src

Writing Your TypeScript Code

Instead of using the basic HTTP module from Node.js, let's use Express.js, a popular web application framework for Node.js that simplifies routing and middleware integration. First, you'll need to install Express and its TypeScript definitions:

bash
npm install express
npm install --save-dev @types/express

Create a new file src/index.ts. This will be the entry point for your application:

src/index.ts
1import express from "express";
2
3const app = express();
4const PORT = 3000;
5
6app.get("/", (req, res) => {
7 res.send("Hello World from TypeScript in Node.js using Express!");
8});
9
10app.listen(PORT, () => {
11 console.log(`Server running on http://localhost:${PORT}`);
12});

In this example:

  • We import and use express.
  • We define a route for the root URL ('/') that sends a response 'Hello World from TypeScript in Node.js using Express!'.
  • We start the server to listen on the specified port.

Adding Scripts to package.json

Modify your package.json to include a build script and a start script:

json
1"scripts": {
2 "build": "tsc",
3 "start": "node dist/index.js"
4}
  • "build" compiles your TypeScript files using the TypeScript compiler.
  • "start" runs your compiled application from the dist directory.

Building and Running Your Application

Compile your TypeScript application

bash
npm run build

This command will create a new dist directory with your compiled JavaScript files.

Run your Node.js application

bash
npm start

This will start the Express server. You can now visit http://localhost:3000 in your browser to see your application in action.

Building a realistic example

Let’s create a more realistic example of an application that simulates the retrieval of data from a database and displaying it.

Create the database files

To keep things simple for the time being, let’s create the database with some static files:

src/db/persons.ts
1export default [
2 {
3 name: "John Doe",
4 },
5 {
6 name: "Jane Doe",
7 },
8 {
9 name: "John Smith",
10 },
11 {
12 name: "Jane Smith",
13 },
14];
src/db/cars.ts
1export default [
2 {
3 id: 1,
4 make: "BMW",
5 model: "X5",
6 year: 2019,
7 owner: "John Doe",
8 },
9 {
10 id: 2,
11 make: "Audi",
12 model: "Q7",
13 year: 2018,
14 owner: "John Smith",
15 },
16 {
17 id: 3,
18 make: "Mercedes",
19 model: "GLE",
20 year: 2017,
21 owner: "Jane Doe",
22 },
23 {
24 id: 4,
25 make: "Toyota",
26 model: "RAV4",
27 year: 2016,
28 owner: "Jane Smith",
29 },
30];

Create the data models

Let’s create some classes to model the entities within these “databases”.

src/model/Car.ts
1/**
2 * Represents a car in the system.
3 */
4export default class Car {
5 private id: number;
6 private make: string;
7 private model: string;
8 private year: number;
9 private owner: string;
10
11 constructor(
12 id: number,
13 make: string,
14 model: string,
15 year: number,
16 owner: string
17 ) {
18 this.id = id;
19 this.make = make;
20 this.model = model;
21 this.year = year;
22 this.owner = owner;
23 }
24
25 public getId(): number {
26 return this.id;
27 }
28
29 public getMake(): string {
30 return this.make;
31 }
32
33 public getModel(): string {
34 return this.model;
35 }
36
37 public getYear(): number {
38 return this.year;
39 }
40
41 public getOwner(): string {
42 return this.owner;
43 }
44}

Here is the final model:

src/model/Person.ts
1import Car from "./Car";
2
3/**
4 * Represents a person in the system.
5 */
6export default class Person {
7 private id: number;
8 private name: string;
9 private car: Car;
10
11 constructor(id: number, name: string, car: Car) {
12 this.id = id;
13 this.name = name;
14 this.car = car;
15 }
16
17 public getId(): number {
18 return this.id;
19 }
20
21 public getName(): string {
22 return this.name;
23 }
24
25 public getCar(): Car {
26 return this.car;
27 }
28
29 public greet(): string {
30 return `Hello, ${
31 this.name
32 }. You drive a ${this.car.getYear()} ${this.car.getMake()} ${this.car.getModel()}.`;
33 }
34}

Create App class to write the business logic

The app class handles the business logic and handles the requests sent to the server:

src/app.ts
1// Models
2import Person from "./model/Person";
3import Car from "./model/Car";
4
5// Static imports
6import persons from "./db/persons";
7import cars from "./db/cars";
8
9export default class CarApp {
10 public greetUser(id: number) {
11 const personName = persons[id - 1].name as string;
12 if (!personName) {
13 return "Person not found";
14 }
15 const carData = cars.find((car) => car.owner === personName);
16 const car = new Car(
17 carData.id,
18 carData.make,
19 carData.model,
20 carData.year,
21 carData.owner
22 );
23 const person = new Person(id, personName, car);
24 return person.greet();
25 }
26
27 public getUser(id: number) {
28 const personName = persons[id - 1].name as string;
29 if (!personName) {
30 return "Person not found";
31 }
32 const carData = cars.find((car) => car.owner === personName);
33 const car = new Car(
34 carData.id,
35 carData.make,
36 carData.model,
37 carData.year,
38 carData.owner
39 );
40 return {
41 id,
42 name: personName,
43 car: {
44 id: car.getId(),
45 make: car.getMake(),
46 model: car.getModel(),
47 year: car.getYear(),
48 },
49 };
50 }
51}

Update the entry point index.js file

Let’s add new write handlers to invoke these business methods:

typescript
1import express from "express";
2
3import CarApp from "./app";
4
5const server = express();
6const PORT = 3000;
7const app = new CarApp();
8
9server.get("/", (req, res) => {
10 res.send("Hello World from TypeScript in Node.js using Express!");
11});
12
13// Route to greet user
14server.get("/greet/:id", (req, res) => {
15 let id = parseInt(req.params.id);
16 res.send(app.greetUser(id));
17});
18
19// Route to get user data
20server.get("/user/:id", (req, res) => {
21 let id = parseInt(req.params.id);
22 res.json(app.getUser(id));
23});
24
25server.listen(PORT, () => {
26 console.log(`Server running on http://localhost:${PORT}`);
27});

Build and launch the server

bash
npm run build
npm start

You can visit the following URLs to access the new paths:

http://localhost:3000/greet/2 and http://localhost:3000/user/3

Conclusion

You've just set up and created your first Node.js application using TypeScript and Express! Express simplifies the server creation and routing, making it easier to build complex applications. TypeScript provides static typing and other modern language features that enhance the development experience and maintainability of your application.

To further your knowledge and exploration in using TypeScript with Node.js and Express, here are some useful resources:

This combination of Node.js, Express, and TypeScript is a powerful toolkit for building robust web servers and applications. Happy coding!

Feedback