Some of you might already use Typescript on all of your projects, maybe for frontend application or backend application. There're also a few Nodejs frameworks that already support Typescript with no config required. I myself still using ExpresJS with plain Javascript, because some of my coworkers are not using Typescript or familiar with it, so that's the best choice for me. Typescript is really useful for us to prevent bugs in the development phase, yup, Type definitions do their job very well. But, not every Nodejs frameworks support it by default, in this case ExpressJS, we need to configure it to make it work in ExpressJS environment.
There are so many examples we can find in the internet about how to configure or using ExpressJS using Typescript, but in this article I'd like to share mine.
Prerequisite
We will start from scratch. First create a directory and install ExpressJS and Typescript packages for our project.
mkdir express-with-typescript; cd express-with-typescript; npm init -y; npm i express typescript ts-node tslib
The project structure for this project would be like the following example. Ignore it for now, please jump to the next step.
express-with-typescript/
|__src/
|controllers/
|__index.controllers.ts
|__interfaces/
|__routes.interfaces.ts
|__routes/
|__index.route.ts
app.ts
server.ts
nodemon.json
package.json
tsconfig.json
Create a Basic App
We will create a very basic example at the moment. Create 2 files, app.js
and server.js
.
// app.js =====
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('hello index');
});
module.exports = app;
// server.js =====
const app = require('./app');
const port = 3000;
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
We are done here, now let's start to configure Typescript for our simple app.
Configure Typescript
In our root directory, create a file called tsconfig.json
. More info about this file, please check Typescript documentation.
{
"compileOnSave": false,
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"allowJs": true,
"baseUrl": "src",
"declaration": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"forceConsistentCasingInFileNames": true,
"importHelpers": true,
"lib": ["es2017", "esnext.asynciterable"],
"moduleResolution": "node",
"module": "commonjs",
"noEmit": false,
"outDir": "./dist",
"pretty": true,
"paths": {
"@/*": ["*"],
"@routes/*": ["routes/*"],
"@interfaces/*": ["interfaces/*"],
"@controllers/*": ["controllers/*"],
"@utils/*": ["utils/*"]
[...] more directory here
},
"resolveJsonModule": true,
"sourceMap": true,
"target": "es2017",
"typeRoots": ["node_modules/@types"]
},
"exclude": ["node_modules"]
}
The compilerOptions
is our main configuration. Inside that block, you can configure how the transpile works on our project. See the paths
block in this example, you can mapping your modules inside that block, you can read TSConfig page for more detail.
Our project is not ready yet. Next, we need to install @types/node
package. This package is used to load in all type definitions when using typescript in node, and we need to install additional packages for our project.
npm i -D @types/node @types/express tsconfig-paths
Now, we need to modify our previous code to become a Typescript files. Change .js
to .ts
, then update the content with the following code.
// app.ts ===================
import express from 'express';
import Routes from '@interfaces/routes.interface';
class App {
public app: express.Application;
public port: string | number;
constructor(routes: Routes[]) {
this.app = express();
this.port = 3000;
this.initializeMiddlewares();
this.initializeRoutes(routes);
}
public listen() {
this.app.listen(this.port, () => {
console.log(`App listening on the port ${this.port}`);
})
}
private initializeMiddlewares() {
// more middewares here...
this.app.use(express.json());
}
private initializeRoutes(routes: Routes[]) {
routes.forEach(route => {
this.app.use('/', route.router);
});
}
}
export default App;
// server.ts =====================
import App from '@/app';
import IndexRoute from '@routes/index.route';
const app = new App([new IndexRoute()])
app.listen()
As you can see, I am using mapping for modules, interfaces
& routes
, because I setup its paths
(based on the project structure) inside compilerOptions
. You can add more modules if you want, but do not forget to update your compilerOptions
configuration. Now create that directories and its file.
mkdir -p express-with-typescript/{controllers/,interfaces/,routes/}
touch express-with-typescript/{controllers/index.controllers.ts,interfaces/routes.interface.ts,routes/index.route.ts}
Then, put these code on each files.
// index.controllers.ts
import { NextFunction, Request, Response } from 'express';
class IndexController {
public index = (req: Request, res: Response, next: NextFunction): void => {
try {
res.send('hello index');
} catch (error) {
next(error);
}
};
}
export default IndexController;
// routes.interface.ts ==========
import { Router } from 'express';
interface Route {
path?: string;
router: Router;
}
export default Route;
// index.route.ts ==============
import { Router } from 'express';
import Route from '@interfaces/routes.interface';
class IndexRoute implements Route {
public path = '/';
public router = Router();
constructor() {
this.initializeRoutes();
}
private initializeRoutes() {
this.router.get(`${this.path}`, () => {
console.log('hello index')
});
}
}
export default IndexRoute;
We are almost done, before run our application, create nodemon.json
file with the following configuration.
{
"watch": ["src"],
"ext": "ts,js",
"exec": "ts-node -r tsconfig-paths/register --transpile-only src/server.ts"
}
And put a start
script inside package.json
file.
"scripts": {
"start": "nodemon"
}
You can now run the application by npm run
command, and try to access it through port 3000, you will see hello index
text as the result. So, that's how I use Typescript in my node projects, I hope it's useful for you. By the way, you might want to consider a framework that's already support Typescript like NestJS, i strongly recommend it.