In the previous post, we set up a basic Node.js and Express server using JavaScript. While JavaScript is a powerful language, it lacks static type checking, which can lead to runtime errors and make it harder to catch bugs during development. TypeScript addresses this issue by adding optional static typing to JavaScript, allowing us to catch errors during compilation and providing better tooling and code organization.
In this post, we’ll integrate TypeScript into our project and convert our existing JavaScript code to TypeScript.
First, we need to install TypeScript as a development dependency in our project:
npm install typescript --save-dev
We add typescript
as a development dependency because it’s only required during the development phase to compile TypeScript code into JavaScript. The compiled JavaScript code is what we’ll run in production.
Next, we need to create a tsconfig.json
file in the root of our project. This file defines the TypeScript compiler options and project settings. Run the following command to generate a basic tsconfig.json
file:
npx tsc --init
This command creates a tsconfig.json
file with default settings. You can customize these settings according to your project’s needs, but for now, we’ll keep the default configuration.
To take full advantage of TypeScript’s features when working with Node.js and Express, you need to install the type definitions for these libraries. These definitions enable TypeScript to understand the types of Node.js and Express objects and functions, providing better code completion (IntelliSense) and catch compile-time errors before they occur.
You can install these type definitions as a development dependency using npm:
npm install @types/node @types/express --save-dev
Now, TypeScript can recognize the types used in Node and Express, providing a more robust and error-free development experience.
Now that we have TypeScript installed and configured, let’s convert our existing server.js
file to TypeScript.
Rename server.js
to server.ts
.
Open the server.ts
file and modify the code as follows:
import express, { Express, Request, Response } from "express";
const app: Express = express();
const port = 3000;
app.get("/", (req: Request, res: Response) => {
res.send("Hello, World!");
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
Here’s what we’ve changed:
require
statement.app
variable and the req
and res
parameters in the route handler function.To run the TypeScript server, we need to compile the TypeScript code to JavaScript first. We can do this by updating the start
script in our package.json
file:
"scripts": {
- "start": "node server.js",
+ "start": "tsc && node server.js",
},
The new script first compiles the TypeScript code using the tsc
command (TypeScript Compiler), and then runs the compiled JavaScript file (server.js
) using node
.
Now, you can run the server using the following command:
npm run start
You should see the same “Server is running on port 3000” message in the terminal, and the server should be up and running.
ts-node
for DevelopmentTo simplify your development workflow, we’ll combine ts-node
with nodemon
. Nodemon will automatically restart your server whenever you make changes to your code. Meanwhile, ts-node enables you to run TypeScript code without needing to compile it separately first.
First, install ts-node
as a development dependency:
npm install ts-node --save-dev
Next, we need to update our dev
script in the package.json
file to use ts-node
and nodemon
.
"scripts": {
- "dev": "nodemon server.js"
+ "dev": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/server.ts"
}
Here’s what this script does:
nodemon --watch 'src/**/*.ts'
: This tells nodemon
to watch all TypeScript files in the src
directory and its subdirectories for changes.-exec 'ts-node' src/server.ts
: This instructs nodemon
to execute ts-node
on our server.ts
file whenever it restarts the server.Now, you can start your server in development mode using the following command:
npm run dev
With this setup, your server will automatically restart, and your TypeScript changes will take effect immediately whenever you modify a file in your src
directory.
ts-node
and tsc
?tsc
(TypeScript Compiler) and ts-node
are both tools that deal with TypeScript code, but they serve different purposes in a project.
tsc
is the TypeScript compiler that transforms TypeScript code into plain JavaScript code. It performs type-checking and compiles TypeScript into JavaScript that Node.js or a browser can execute. The compiled JavaScript code is usually used for production environments.
On the other hand, ts-node
is a tool that’s primarily used for development purposes. It allows you to execute TypeScript code directly, without the need for a separate compilation step. It combines the TypeScript compiler with a runtime environment (Node.js), so you can run your TypeScript code just like you would run JavaScript code. This is particularly useful during development as it helps to streamline the development process and enables hot-reloading capabilities.
By integrating TypeScript into our project, we’ve added static type checking and better tooling support, which can help catch errors during development and improve code maintainability. In the following post, we will arrange our project folder structure to distinguish between source and compiled files.