Four Ways to Utilize the TypeScript Compiler for Improved Type-Checking

Sébastien Raynaud
La Mobilery
Published in
5 min readFeb 14, 2024

tl;dr

  1. Command line interface (npx tsc --noEmit)
  2. Automatic task (VSCode)
  3. Pre-commit (husky)
  4. Continuous integration step (GitHub action)

TypeScript compilation

JavaScript is most used programming language on GitHub in 2023¹. It is not a strongly typed language, which means that no errors are detected when writing, for example, a number as an argument to a function that is only supposed to accept text. However, an error may occur when trying to execute the code.

// codeWithError.js

const formatText = (text) => text.toUpperCase()
formatText(3)
// No warning in the IDE when writing this code, in VSCode for example
// When executing this code, we get the following error:
// Uncaught TypeError: text.toUpperCase is not a function

TypeScript is a superset of JavaScript that adds syntax for types. To be executed, a TypeScript file must first be compiled to JavaScript (more precisely: transpiled).

During compilation, an error is raised immediately by the TypeScript compiler if a variable does not match its expected type. There is no need to wait for code execution to detect errors.

// codeWithError.ts

const formatText = (text: string) => text.toUpperCase()
formatText(3)
// The compilation step detects the following error:
// Argument of type 'number' is not assignable to parameter of type 'string'.

Detecting compilation errors

When using a development environment that includes support for TypeScript, such as VSCode, compilation errors can be detected as soon as the file with the error is opened.

Example of TypeScript compilation error in VSCode

However, this also means that errors are not detected until the file is opened. There may be other files with compilation errors, and checking every file manually is not really practical.

That’s where the TypeScript compiler, tsc, comes to the rescue.

1. Command line

Based on the project’s tsconfig.json, the TypeScript compiler allows you to detect all errors in a project. Its most basic use is npx tsc from the command line.

Compiler options² can be added, such as:

  • --noEmit to avoid building JavaScript output if we only want to check the compilation
  • --watch, eventually, to run the compilation again each time a file is updated

For a one-time compilation check: npx tsc --noEmit

For a continuous compilation check: npx tsc --noEmit --watch

“npx tsc --noEmit” detecting a compilation error without having to open any file

Tip: if you regularly use npx tsc --noEmit, create an alias. For example alias tscheck="npx tsc --noEmit” in .zshrc.

2. Automatic task

This section focuses on VSCode, feel free to comment on this article with how to do this in your favorite IDE.

VSCode has built-in tasks for checking TypeScript compilation. In your TypeScript project, press ⌘+Shift+B (Windows: Ctrl+Shift+B) to display the list of available tasks. Choose tsc: watch - tsconfig.json in the list to run the TypeScript compiler in watch mode (similar to npx tsc --noEmit --watch).

Tasks available in VSCode after initialization of a TypeScript project (⌘+Shift+B / Ctrl+Shift+B)

Tasks can be configured to execute automatically when opening a project by adding the run option "runOn": "folderOpen"³. Here is an example for a TypeScript compilation check automatic task. This file should be located at .vscode/tasks.json:

{
"version": "2.0.0",
"tasks": [
{
"type": "typescript",
"tsconfig": "tsconfig.json",
"option": "watch",
"problemMatcher": [
"$tsc-watch"
],
"group": "build",
"label": "tsc: watch - tsconfig.json",
"runOptions": {
"runOn": "folderOpen"
}
}
]
}

This task can execute automatically only if the user has allowed automatic tasks. To allow automatic tasks: open the command panel with ⌘+Shift+P (Windows: Ctrl + Shift + P), search for Tasks: Manage Automatic Tasks, and then Allow Automatic Tasks, as demonstrated below.

3. Pre-commit

To avoid pushing code containing compilation errors to a repository, the compilation can be checked in pre-commit, for example using husky⁴.

First, create a script in package.json that executes the TypeScript compiler. No need to use npx, tsc is already available here if your project uses TypeScript.

{
"scripts": {
"tscheck": "tsc --noEmit"
}
}

Then, setup husky using their documentation and replace the content of .husky/pre-commit by npm run tscheck to use the new script from package.json.

After that, the TypeScript compiler will be executed in pre-commit to avoid pushing code containing errors.

4. Continuous integration

This section focuses on GitHub actions, feel free to comment on this article with how to do this in your favorite continuous integration environment.

The most critical step at which compilation should be checked is before merging code to the main branch of a repository. For a GitHub repository, this can be done using GitHub actions⁵.

Here is an example of workflow to perform a compilation check when a pull request is opened to the main branch. This file should be located at .github/workflows/check-typescript-compilation.yml:

name: Check TypeScript compilation
on:
pull_request:
branches:
- main
types:
- opened
jobs:
typecheck:
name: Check TypeScript compilation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install packages
run: npm i
- name: Check TypeScript compilation
run: npm run tscheck

For more information about GitHub actions, see the documentation.

Conclusion

This article presents four tools to help detect TypeScript compilation errors. They should not necessarily all be used together in a project.

The command line is especially useful in a project that does not include other ways to check TypeScript compilation, as it is always available even if the project’s configuration cannot be changed.

Automatic tasks in watch mode are a good way to detect errors immediately and set up the project so that other developers benefit from it without having to configure it themselves. However, depending on the work performed, checking the compilation after every file save may not be necessary and consume resources without any benefit.

Pre-commit provides a good opportunity to regularly check if compilation errors have been introduced. Additionally, it can be ignored if needed by adding --no-verify to the commit options, e.g. git commit -m "wip" --no-verify.

Finally, integrating compilation checks into a continuous integration process is critical and can be achieved using a tsc command. However, a specific check like this may not always be necessary, as compilation would also be verified if there is a build step in the continuous integration process.

References

  1. Top 10 programming languages on GitHub, GitHub Blog, https://github.blog/2023-11-08-the-state-of-open-source-and-ai
  2. TypeScript Compiler Options, https://www.typescriptlang.org/tsconfig
  3. Integrate with External Tools via Tasks, VSCode docs, https://code.visualstudio.com/docs/editor/tasks
  4. Husky, https://typicode.github.io/husky
  5. GitHub Actions - Automate your workflow from idea to production, https://docs.github.com/en/actions/quickstart

--

--