Set up Node.js project with Typescript, ESLint, and Prettier

Set up Node.js project with Typescript, ESLint, and Prettier
Photo by Steve Harvey on Unsplash

Photo by Steve Harvey on Unsplash

TypeScript is a free and open-source programming language developed by Microsoft that aims to improve and secure JavaScript code production.

This is a superset of JavaScript (that is, any correct JavaScript can be used with TypeScript).

TypeScript code is transpiled in JavaScript and can be interpreted by any web browser or JavaScript engine. The first version was released in 2012.

Typescript brings more comfort in the writing of the syntax. It’s a good choice to use it because :

  • An optional static type of variables and functions
  • Object-oriented programming support
  • Module import
  • It supports the ECMAScript 6 specification.
  • The ability to compile down to a version of JavaScript that runs on all browsers.
  • IDE provides IntelliSense to make you write the code faster.
  • Helps you implement SOLID principles into a language that doesn’t really support it.
  • The code is easier to test.


For this tutorial, you need to have these tools installed:

Node.js come with NPM, which can be used to install Node modules, so feel free to use it. I will use Yarn.

Initialize node project

Create a new folder and go inside:

mkdir node-typescript-starter

cd node-typescript-starter

Since we are inside the folder, we will initialize a Node.js project by running the command yarn init then you will have to answer some questions.

We get the output below:

Initialize a Node.js project

A file named package.json will be created, and it is the configuration file for a Node.js project.

Add typescript

Run the commands below to install Typescript:

yarn add typescript
yarn add -D @types/node

The first line installs Typescript in the project, and the second line installs the definitions of the types of modules that come with Node.js, like http, fs, path, cluster, etc...

Note that the CLI option -D the second command indicates that we want to install this package only for development, so it will not be installed if we are in production mode.

Now we need to set up the configuration for Typescript. It consists of a file where we define rules that Typescript will use to check and build our code.

For example, Which version of Javascript we are targetting, directories to exclude or include in type checking, enable or disable some type check rule, and so on.

yarn tsc --init
# or
npx tsconfig.json

These two commands have the same goal but produce different results.

  • The first command generates a tsconfig.json file with comments on each property, which helps understand the purpose of this last. I will recommend this command to someone who just starting with Typescript.
  • The second command generates a tsconfig.json file with many predefined properties already configured, contrary to the first, which has few properties. I recommend this for someone already familiar with Typescript.

You can customize the tsconfig.json as you want. I will provide the one I use on all my projects in the project repository at the end.

Write code

Create a folder, then add a file named index.ts. Feel free to use your preferred editor or IDE.

mkdir src
cd src
touch index.ts

Open index.ts and paste write the code below, and save:

const addition = (a: number, b: number): number => {
    return a + b;

const number1: number = 5;
const number2: number = 10;
const result: number = addition(number1, number2);

console.log('The result is %d', result);

Execute the project

We wrote our super function, which calculates the sum of two numbers, and we want to execute it. I will tackle this in 3 steps to show you all possibilities.

Compile the file, then run it with the node

The Node.js runtime runs javascript code only, and since it is in Typescript, we have to translate it to javascript and then run it. We achieve this by running the command below:

# Inside the folder node-typescript-starter
yarn tsc
node build/index.js

The output will be similar to the picture below:


Run the Typescript file directly

Now we can execute our code, but we must run to command to see the result. Why can we just execute our .ts file directly? Also, we only need JavaScript files when we want to deploy them in production.

Hopefully, it's possible through a Typescript runner called ts-node. We will first install it and then run our project with the command below:

# We only need it for development
yarn add -D ts-node 

Run the command below to execute the Typescript code:

yarn ts-node src/index.ts

Execute the file on changes

Now we can run our file with one command instead of two, but I find it hard to run this command every time I have to make a change in my files. Is there a way to run files on change? (Yess, I'm a lazy developer).

Hopefully, there is a package called nodemon which can do this for us, so let's install it and then see our to use it.

yarn add -D nodemon

Before you start editing your files, you just need to run this command:

nodemon --watch "*.ts" --exec "ts-node" ./src/index.ts

This command means: Watch every change on all files with the extension .ts, then use ts-node to run them by using the located at ./src/index.ts as the entry point.

If you want to add another file to watch, for example, a .json file, add another CLI option --watch followed by ".json"

nodemon --watch "*.ts"  --watch "*.json" --exec "ts-node" ./src/index.ts

Configure ESLint and Prettier

ESLint helps us write better code by checking if our code is well-written, and well-formatted, and respects some rules defined as the best practices for maintainable and consistent code.

Let's install the necessary dependencies:

yarn add -D eslint eslint-config-prettier eslint-plugin-prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser

Create a file .eslintrc.js in the root folder of the project and add this code:

module.exports = {
  parser: '@typescript-eslint/parser',
  extends: ['plugin:@typescript-eslint/recommended', 'prettier/@typescript-eslint', 'plugin:prettier/recommended'],
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: 'module',
  env: {
    es6: true,
    node: true,
  rules: {
    'no-var': 'error',
    semi: 'error',
    indent: ['error', 2, { SwitchCase: 1 }],
    'no-multi-spaces': 'error',
    'space-in-parens': 'error',
    'no-multiple-empty-lines': 'error',
    'prefer-const': 'error',

The important part of the code below is the rules property. It is here we define our rule.

For example: semi: 'error' means a semicolon is required at the end of an instruction.
prefer-const means the use of let is forbidden, and the use const instead.

You can find available rules here, and feel free to customize them as you want.
If a rule is not respected, the line will be underlined with a red or orange line depending on if you set the error level for this specific rule to error or warning respectively.

Create a file .prettierc at the root folder and add the code below:

module.exports =  {
  semi: true,
  trailingComma: 'all',
  singleQuote: true,
  printWidth: 150,
  tabWidth: 2,

In this file, we define rules that prettier will use to format our code for us.
semi: true means prettier would add a semicolon at the end of a line if we forgot to do that.
tabWidth: 2 means prettier will indent lines with two spaces.

Add a script in our package.json to fix all ESLint errors:

"scripts": {
  "eslint:fix": "eslint --fix",

Now run yarn eslint:fix to see the command in action

Bonus: Type Inference

Typescript has a great feature that consists of guessing the variable type based on the value assigned to the last one or guessing the return type of a function based on the value returned.

Let see some examples:

const isValid: boolean = true; // type is explicit

let age: = 44; // Typescript will give the type of value `5` to the variable `age` which is a Number

const word = "5"; // Typescript will do the same so `word` is a type String

number = word; // Typescript will show and error because a String can't be assigned to a number.

We can refactor our code to remove unnecessary types. The advantage of doing that is that our code will be more readable and avoid boilerplate code.

const addition = (a: number, b: number) => { // Typescript will guess the function returns a number
    return a + b;

const number1 = 5;
const number2 = 10;
const result = addition(number1, number2); // Result will be a number

console.log('The result is %d', result);

We have a great project starter to build awesome Node.js applications using Typescript.

You can find the code source on the GitHub repository.

Follow me on Twitter or subscribe to my newsletter to avoid missing the upcoming posts and the tips and tricks I occasionally share.