TL;DR: Download/clone this Github example and modify it to your requirements.

Having a proper working debugger is a massive improvement in productivity in any IDE, and in my case it was the key decision to switch to Visual Studio Code for working with JavaScript in Node.js. However, with gulp and the directory structure we are using, the debugger does not work by default in TypeScript, so we have to tweak some of the settings to make it work.

First, we have to set up the build system to emit source maps, which are files that map TypeScript code to the corresponding JavaScript code. In this manner, when we set a breakpoint at a particular line in TypeScript, it will break in the correct line in JavaScript. The following is a minimal gulpfile that takes all TypeScript source files from the /src directory and outputs the compiled JavaScript in the /app directory:

var gulp = require('gulp');
var ts = require('gulp-typescript');
var sourcemaps = require('gulp-sourcemaps');

var tsProject = ts.createProject('tsconfig.json');

gulp.task('default', function() {
	return gulp.src("src/**/*.ts")
	.pipe(sourcemaps.init())
	.pipe(tsProject())
	.pipe(sourcemaps.write("."))
	.pipe(gulp.dest("./app"));
});

This code should be self-explanatory. TypeScript supports the source maps plugin, therefore we can use that plugin to generate the source maps. We include it in line 3, initiate it in line 10, and write the source maps in line 12. The source maps are written along side the output JS source code.

In line 5 and 11, we define and use a tsConfig.json file instead of setting our compiler options straight in the gulp code. tsConfig.json is the Microsoft-approved way to set the TypeScript compiler settings, so we will be using it going forward. With this file we gain an improvement in the portability of our TypeScript settings and the ability to use the full range of options that may not be available to the gulp-typescript package. Finally, using the tsConfig.json file allows us to set the options that tell the debugger where to look for the generated source maps that were created earlier.

The following tsConfig.json file gives us a minimal example of the settings we need to set up our working debugger:

{
    "compilerOptions": {
        "target": "es5",
        "lib":["es2016","es2016.array.include"],
		"noImplicitAny":false,
		"noEmitOnError":true,
        "removeComments": false,
        "sourceMap": true,
        "rootDir": "./src",
        "outDir": "./app",
        "mapRoot": "./app"
    },
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "node_modules",
        "**/*.spec.ts"
    ]
}

Take note of lines 8 through 12. The options on those lines enable the source maps, set the root directory of the TypeScript files, set the output directory of the JavaScript files, and set the root directory of the source maps. Although some of these options are duplicates of the options on the gulpfile, it’s a good idea to have them defined here as well for documentation and portability purposes.

This should be enough to make the Visual Studio Code debugger work with compiled TypeScript files. If you have any trouble, download the example project from the repository at the top of this article for an example of a project with a working debugger.