TypeScript-support for Node.js is provided by the
typescript NPM package. The best way to implement this package will depend on your project's build tooling. If you have webpack set up, then the easiest way will be by using the
ts-loader package (see the "Setting up ts-loader for webpack" section below for this
typescript setup). However, if you don't have a module bundler configured, then the simplest way to add TypeScript will be through the
tsc ("TypeScript compiler") command, which is included in the
typescript package. This
tsc setup is described next.
The first order of business is adding the
typescript package to your project as a dev-dependency:
npm install --save-dev typescript
The next step is to create a config file for
typescript. A good starting point is to generate the file using the command
npx tsc --init. Add the following properties to the
compilerOptions property in the generated file:
"noImplicitAny": true— Disallows the use of the
anytype - a common anti-pattern in TypeScript.
After adding these properties the tsconfig.json looks as follows:
And just like that, the code is ready to be compiled! Just run the command
npx tsc and see the output files appear in the dist folder.
"type" property in your package.json from
"commonjs" in order to run the compiled code (tsc will still interpret your source code as ES modules). At this point the "main" .js file in the dist folder should run successfully via the
A side-effect of running the compiled code instead of running the source code directly is that stack traces of errors will refer to the line numbers inside the compiled code instead of in the source code, which is not very helpful. Luckily we can have tsc generate source map files which map each line in the compiled code to the corresponding line in the source code. These can be used to make our application report the correct line numbers in error stack traces.
Getting tsc to generate the source map files is an easy matter of adding the
"sourceMap": true property to the
"compilerOptions" in tsconfig.json:
npx tsc again and note that in the dist folder a .js.map file is created for each compiled .js file. However, we still need to make these mappings be interpreted at run-time. To do this, add the
source-map-support package as a run-time dependency. We also add its types declaration package for TypeScript as a dev-dependency:
npm install --save source-map-support npm install --save-dev @types/source-map-support
And activate it by adding the following to your main source file:
Compile and run the application. Error stack traces will now refer to the lines in the source code.
Creating script commands (in package.json) for compiling and running the application is pretty simple:
"build": "tsc", "run": "node dist/my-app.js",
For a streamlined developer experience we would want to have a command that will listen for source file changes and then recompile and restart the application whenever they occur.
tsc command conveniently has a
--watch flag we can use to recompile. Then we can use the
nodemon package to restart the application whenever we detect file changes in the dist folder (due to the recompilation). Hence we can have the following two scripts:
"build:watch": "tsc --watch", "run:watch": "nodemon dist/my-app.js --watch dist",
But we need these two commands to run at the same time. This can be achieved using the
Add the required packages as dev-dependencies:
npm install --save-dev nodemon npm-run-all
Final list of scripts:
"build": "tsc", "run": "node dist/my-app.js", "build:watch": "tsc --watch", "run:watch": "nodemon dist/my-app.js --watch dist", "start": "npm-run-all --parallel build:watch run:watch"
npm start to compile and run the application. Whenever you make a change to a source file, the application will automatically recompile and then restart.
If your application already has build tooling set up via webpack, the easiest way to add TypeScript support is by using the
This time around, add the
typescript packages as dev-dependencies:
npm install --save-dev ts-loader typescript
The same tsconfig.json configuration file as above can be used in this case:
js in the "test" property of the rule added to webpack.config.js below.
In webpack.config.js add a rule telling webpack to invoke ts-loader for all TypeScript files:
At this point the application should build and run fine. We are now ready to start converting .js files to .ts files.
"allowJs": true flag in the tsconfig.json can be removed.
Here are some general notes to observe during this conversion:
"strict": true setting in the tsconfig.json causes
If you have defined any sub-classes of
Error, note that there is a known bug in TypeScript whereby testing for an instance of this error using
instanceof will not work.
See this StackOverflow post for a work-around. If you have multiple sub-classes of
Error, I would recommend applying the work-around to a common "base" error class (eg.
class ErrorBase extends Error) and have all other error classes extend this class.
Alternatively, if your code need not support running on IE 11, you should be able to safely change the compiler target from ES5 to ES6 by changing the
"target" property in tsconfig.json to
"es6" (see the ES6 compatibility chart). This way tsc will generate all classes as actual ES-classes in the target code, effectively circumventing the bug and obviating the need for the work-around.