TypeScript is a statically typed superset of JavaScript. JavaScript engines can’t interpret TypeScript code, so you have to compile your TypeScript code to regular JavaScript code before you can run it. Let’s look at a few ways to do this in Node.js, a JavaScript runtime environment that exists outside the browser.

node

Because TypeScript is a superset of JavaScript, all JavaScript code is valid TypeScript code, but not the other way round. If you have a TypeScript file that contains no TypeScript syntax, you can run it directly in Node.js. For example, if you had an index.ts file as follows:

function greet(name = "World") {
console.log(`Hello, ${name}!`);
}

greet();

You could simply run node ./index.ts in your shell (assuming index.ts was relative to your current working directory). It would work because this TypeScript code is valid JavaScript code. Therefore, the Node.js runtime environment could interpret it.

tsc

Once you annotate your JavaScript code with TypeScript syntax, you can no longer run it directly in Node.js. You’ll get a SyntaxError. For example, let’s annotate the parameter and return types of the greet() function:

function greet(name: string = "World"): void {
console.log(`Hello, ${name}!`);
}

greet();

If you try to run node ./index.ts, you’ll get a SyntaxError similar to the following. The Node.js runtime environment can only interpret regular JavaScript code, so it won’t understand the type annotation:

function greet(name: string = "World"): void {
^

SyntaxError: Unexpected token ':'
at internalCompileFunction (node:internal/vm:73:18)
at wrapSafe (node:internal/modules/cjs/loader:1178:20)
at Module._compile (node:internal/modules/cjs/loader:1220:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Module._load (node:internal/modules/cjs/loader:960:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:23:47

Before you can compile the TypeScript code, you need to install the TypeScript compiler (tsc). The following list of commands creates a package.json file, installs the TypeScript compiler as a development dependency, and creates a tsconfig.json file. You can skip these steps if you already have these things.

  1. npm init --yes
  2. npm install typescript --save-dev
  3. npx tsc --init

To compile the TypeScript code, you can run npx tsc ./index.ts, assuming index.ts is in your current working directory. By default, the compiled JavaScript code will be placed in a file called index.js in the same directory. To run it, enter node ./index.js in your shell.

This works, but you’ll have to manually compile and run the code every time you make a change.

tsc --watch

To automatically compile your TypeScript code every time you make a change, you can use the TypeScript compiler’s --watch flag:

npx tsc ./index.ts --watch

However, you’ll still need to manually enter node ./index.js in your shell to run the compiled JavaScript code.

ts-node

To begin streamlining this process, you can install the ts-node package. This is a TypeScript engine that compiles your TypeScript code just in time (JIT), meaning you can skip the manual compilation step.

  1. npm install ts-node --save-dev
  2. npx ts-node ./index.ts

The downside of this approach is that you can’t watch your TypeScript files for changes. You have to run them every time you make a change.

nodemon

nodemon is a package that monitors your JavaScript code and re-runs it when it detects changes. You can use nodemon and ts-node together to monitor your TypeScript code. You need to install both packages because nodemon needs ts-node to work with TypeScript.

npx nodemon ./index.ts

Summary

  1. If your TypeScript file contains only JavaScript code, you can run it directly in Node.js.
  2. Once you add TypeScript syntax, you need to compile your TypeScript code using the TypeScript compiler (tsc) before running it.
  3. To automatically compile your TypeScript code every time you make a change, you can use the TypeScript compiler’s --watch flag. You’ll still need to manually run the compiled JavaScript code.
  4. To skip the manual compilation step altogether, you can install the ts-node package. It’s a TypeScript engine that compiles your code just in time (JIT).
  5. To run your TypeScript code directly and have it re-run every time you make a change, you can use the nodemon and ts-node packages together. The nodemon package monitors your code and re-runs it when it detects changes.