Debugging in Visual Studio Code with TypeScript

Visual Studio Code has the capability to run and debug many types of applications. With its built-in support for recognizing TypeScript files, it is not surprising that it has support for debugging TypeScript. This is because of Visual Studio Code's built-in support for debugging Node.js applications. Because of that, any languages that can be transpiled to JavaScript can be debugged by providing a mapping file (discussed later). Thanks to Visual Studio's extensible nature, additional support for debugging other languages like C# can be added by installing extensions. In this post, I will show you how to setup TypeScript debugging and the general debugging features of Visual Studio Code.

Getting the Starter Project

We need a simple TypeScript project to demonstrate Visual Studio Code's debugging capabilities. I have discussed how to do this in getting-started-with-typescript. If you follow along and completed my instructions over there, then you can continue with that project. If you are starting from scratch, you can copy or check out the following starter project that you can use as a starting point to follow along. https://git.io/vyOgp

Enabling Source Maps

Since the browser or a JavaScript environment runs the compiled JavaScript and not the original TypeScript file, VS Code or any other debuggers will not be able to easily determine where exactly does a line or part of JavaScript code will map to in the TypeScript code. This problem is also true if you are minifying and bundling JavaScript. Since the minified file is mostly just a single line of code, it's hard to determine which part of that line corresponds to a certain line of the original unminified and unbundled code. This problem is handled by generating source maps. It is basically a mapping of lines and columns from minified, transpiled, or bundled code to their corresponding lines and columns in the original source code which in our case will be TypeScript. VS Code needs this file in order directly debug your TypeScript file.

Fortunately, TypeScript has the capability to generate this source maps for you. All you need to do is to enable sourceMap in your tsconfig.json file. Open your tsconfig.json and set sourceMap to true. It should now look like the following:

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "noImplicitAny": false,
        "sourceMap": true,
        "outDir": "dist",
        "watch": true
    }
}

Simply run the tsc command from the terminal to recompile your TypeScript files using the new configuration in tsconfig.json. Now if you look in the dist folder which is the directory where the transpiled JavaScript resides, you will see another file named app.js.map which has the same name as app.js but has a .map extension. This is the generated source map. VS Code and other debuggers like the Chrome Developer Tools can automatically recognize this file and use it for debugging.

Updating the Launch configuration

Now that we have the source map ready, we can instruct launch.json to use app.ts as our startup program instead of the transpiled JavaScript file. Open launch.json inside the .vscode folder and change the program property of the first configuration to ${workspaceRoot}/app.ts. This is not required and VS Code will still be able to debug the corresponding TypeScript even if the program is set to the transpiled JavaScript file, but my personal preference is to point this to the TypeScript file.

Let's Debug!

Great! We now have our environment ready for debugging TypeScript files. In the starter project, you should see an app.ts file. To start debugging, we must first write some dummy code to debug. Write the following code:

var firstNumber: number = 1;
var secondNumber: number = 2;
var sum: number = firstNumber + secondNumber;

console.log(sum);

Click on the left side of the line number for the console.log line. Breakpoint does what you expect, which is to have the debugger stop its execution at that point so you can inspect things.

Adding A Breakpoint in VS Code

To run an application in Debug mode, you can simply press the F5 key. The program should now stop at the first breakpoint and the line will be highlighted in yellow.

Breakpoint was Hit

Stepping Through Code

Visual Studio Code allows you to step through code just like the debuggers in other IDEs. Once you hit a breakpoint, you can step over, step into, and step out. Let's update the example code in app.ts to the following so we have more code to try out this features.

var firstName: string = "John";
var lastName: string = "Smith";
var dateOfBirth = new Date('1991-03-04');
var today: Date = new Date();

console.log(`Greeting ${firstName} ${lastName}...`);

if (today.getMonth() == dateOfBirth.getMonth() &&
    today.getDate() == dateOfBirth.getDate()) {

    for (let i = 0; i < 3; i++) {
        console.log("Happy Birthday!");
    }
}

console.log("Have a wonderful day!");

Put a breakpoint on the call to console.log call method and hit F5. During debugging, you should see a bar containing debugging controls.

Debugging Toolbar

Here are what these buttons do (in order from left to right):

  1. Play/Pause - When you reach a breakpoint, you can click this button to continue to the next breakpoint or if none, continue with the normal execution of the program.
  2. Step Over - This one allows you to step line by line in your code. If you reach an end of a loop, it will go back to the header of the loop and check if the loop should execute once more.
  3. Step Into - If a line has a function call, this button will navigate you inside that function so you can debug its content.
  4. Step Out - If you are within a function, hit this button to go out of it and navigate back to the immediate caller of that function.
  5. Restart - Simply restarts the application
  6. Stop Debugging - Ends the debugging session

These buttons also have corresponding shortcuts for them. By hitting Ctrl + P to open the Command Palette and typing "Debug", all debug related commands will show up plus the shortcut they are mapped to.

VS Code Debugging Shortcuts

Play around with the debugging by hitting the Step Over/Step Into buttons.

Checking Variable Values

There are more to VS Code debugging than just stepping through code. When debugging, you may want to check the current values of the variables. VS Code allows you to do just that. Again, start the debugging and when you hit the first breakpoint, we can hover over each variable to see their values.

Looking at Variable Values

The above is a contrived example as we can already see the value right next to it, but if you hover over the variable name, a bubble will pop out with its current value. You can also see all in-scope variables in the Variables Section under the Debug View of VS Code.

Variables Pane

Watching Variables and Expressions

VS Codes Debug View also has another section for watching variable values and any valid TypeScript/JavaScript expression. The watch section can be found just below the variables section.

Watch Section

You can click the plus icon to add expressions that you want to watch.

Watch Section

Each expression in the watch section are evaluated and the resulting value is shown right beside them. When you are navigating through your code and modifications are done to the variables involved in the expressions being watched, then the Watch Section will reevaluate the expressions to show updated values.

Determining and Navigating the Call Stack

Reading the call stack allows you to check the chain of methods that lead to the current position you are debugging. The Debug Section has a Callstack Section for showing the current call stack.

Call Stack Section

Clicking on a specific line within this call stack will navigate you to that exact point of code. You can then inspect the variable values or state of the application when it hit that part of your code which is helpful in debugging.

Conditional Breakpoints

There are times when you only want a breakpoint to pause the execution if there are certain conditions met. A good example of this is when you are debugging a certain control within a controls collection, and you added a breakpoint inside a loop that iterates this controls collection. You don't want to hit this breakpoint every single iteration. You want to only stop debugging when the control you want to debug is the control being iterated. You can add a condition to that breakpoint containing an expression that tests for the id property of that control.

For my example code, I will simply pause debugging when a loop hits its second iteration. Place a breakpoint inside the for loop of our example code. To add a condition to that breakpoint, right-click on the breakpoint and choose Edit Breakpoint... Add the expression you want to meet fist before the breakpoint pauses the program. The expressions you should add should be valid and only reference symbols that are in scope of that line.

Conditional Breakpoint

Press the Enter key to commit this change. You should now see an equal sign within the breakpoint. Note that another type of expression you can choose is Hit Count, which means that breakpoint will only take effect when it was hit a certain number of times.

Wrap Up

I certainly missed some debugging features of VS Code. If you want to dig further with this, then you can refer to https://code.visualstudio.com/docs/editor/debugging.