debugging typescript in vs code

2020-08-08

 | 

~4 min read

 | 

648 words

Update: I wrote a follow up to this post that takes a slightly different approach by using source maps for better debugging and focuses on interactive node applications. You can read it here.

One of the few annoyances with writing code in Typescript vs regular Javascript is that you can’t simply run it. You need to compile it first. Normally this isn’t a problem since it’s easy enough to add the compilation step to the build process. The trouble lies when you want to debug your code.

For example, if you had a Javascript file:

index.js
function main(name) {
  console.log(`hello, ${name}.`)
}

main("Stephen")

You could run it from the command line:

% node index.js
hello, Stephen

But what if the file was written in Typescript?

index.ts
export {} // this line simply indicates that we're exporting a module
function main(name: string) {
  console.log(`hello, ${name}.`)
}

main("Stephen")

Running this file from node (not surprisingly) leads to an error:

% node index.ts
(node:24160) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
/Users/stephen/code/temp/tsc-sandbox/index.ts:1
export {};
^^^^^^

SyntaxError: Unexpected token 'export'
    at wrapSafe (internal/modules/cjs/loader.js:1053:16)
    at Module._compile (internal/modules/cjs/loader.js:1101:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
    at Module.load (internal/modules/cjs/loader.js:985:32)
    at Function.Module._load (internal/modules/cjs/loader.js:878:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47

The same file, however, once compiled, works as expected.

% tsc
% node index.js
hello, Stephen.

Configuring VS Code

What if we wanted to use breakpoints and actually debug the file? There are a few things that are necessary which the VS Code team lays out in their post on debugging Typescript:

  1. A source map
  2. Specifying the out files

In our simple example we used the default Typescript settings, so this wouldn’t work. Fixing it requires just a few steps.

In the tsconfig, make sure that sourceMap is set to true and then note the value for outDir (the default is the root).

From there, we can configure a new launch.json for the debugger. We can use the default for the Javascript equivalent - so if we’re launching a node program with the compiled code, that’s what we would want to select:

add configuration

Here’s an example where the outDir setting is set to build and the program’s entry point is index.js. Note that’s .js, not .ts. That’s because when we get to the point of actually launching the debugger it will be with the compiled javascript, not Typescript.

launch.json
{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch TS Node",
      "program": "${workspaceFolder}/build/index.js",
      "preLaunchTask": "tsc: build -p tsconfig.json",
      "outFiles": ["${workspaceFolder}/build/**/*.js", "!**/node_modules/**"]
    }
  ]
}

The other line that is worth looking at is the preLaunchTask - which shows that we’re building our application before we run the debugger.

Another thing worth noting is once this is set up you’re free to change the program to ${file} to debug the current file, i.e. the file that’s open when the Debugger is launched.

And just like that, we’re now able to debug Typescript files with VS Code! Break points and all.

A Word Of Warning - Terminate and Launch, Don’t Restart

One potential “gotcha” is related to the compilation step. Imagine debugging a process and making changes to the source code. With regular javascript files, we can restart the debugger (⇧ + ⌘ + F5) and immediately see the changes take effect. With Typescript, however, that won’t work because restarting isn’t considered launching the debugger. Consequently, the typescript compiler won’t run and the dubugger, which is pointing at a .js file will be outdated. The solution is simple enough: split the step into two. First, stop the debugger (⇧ + F5) and then start it fresh (F5).


Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!