Home

3 ways to watch and run your TypeScript projects

Introduction

One difficulty people can run into when setting up a TypeScript project for the first time is: “How do I build and re-run the project on every code change?”

TypeScript has evolved greatly in the last few years, but running the project after building in watch mode is still not an available feature at the time of this writing.

In this short guide we are having a look at 3 ways this can be accomplished:

  1. Use nodemon and & flag
  2. Use the concurrently package
  3. Use the ts-node-dev package

TLDR; use ts-node-dev. The code for all options is available here.

1. Using tsc -w and nodemon

This is the most straight forward way. Install nodemon:

npm install --save-dev nodemon

Edit scripts in your package.json:

{
  [...]

  "scripts": {
    "start": "tsc && node dist/main.js",
    "watch-and-run": "tsc -w & nodemon -q -w dist dist/main.js"  }

  [...]
}

Explanation:

  1. tsc -w runs the TypeScript compiler in watch mode
  2. & tells the shell to execute the previous command in the background
  3. Nodemon’s -q flag silences restart messages
  4. -w dist tells nodemon which folder to watch
  5. dist/main.js tells nodemon what file to run when changes are detected.

2. Using concurrently

The concurrently way builds on top of the nodemon approach, with added features such as the --kill-others flag, output prefixing, color highlighting and others.

npm install --save-dev concurrently nodemon

Your package.json:

{
  [...]

  "scripts": {
    "start": "tsc && node dist/main.js",
    "watch-and-run": "concurrently --kill-others --names \"BUILD,RUN\" -c \"bgBlue.bold,bgMagenta.bold\" \"tsc -w\" \"nodemon -q -w dist dist/main.js\""  }

  [...]
}

Then pros and cons of options 1 and 2.

The upside of the above methods is that they are simple, and there is no “magic”. You can see exactly the commands being ran, and you have full freedom customize them to your liking.

The downside with the two approaches above is that nodemon does not yet have a flag to skip the first run. This means your main.js starts immediately and will re-start after tsc is done building and replacing the files.

The bellow alternative seek to solve this issue.

3. Using ts-node-dev

This is probably the best and easiest solution at this time. ts-node-dev offers great compile speed and requires zero configuration.

npm install --save-dev ts-node-dev

Your package.json:

{
  [...]

  "scripts": {
    "start": "tsc && node dist/main.js",
    "watch-and-run": "ts-node-dev --respawn -- src/main.ts"  }

  [...]
}

One thing to note is that ts-node-dev does not output the transpiled .js files into a dist folder. This is because it makes use of ts-node under the hood.

Conclusion

TypeScript is evolving very fast and we already have sweet compile features such as watch and incremental.

It’s likely that there will be some sort of --afterBuildCommand flag at some point, but for the time being the above options should serve well for most projects.