DEV Community

Cover image for Run a TypeScript type check in your pre-commit hook using lint-staged + husky
Sam Jones
Sam Jones

Posted on

Run a TypeScript type check in your pre-commit hook using lint-staged + husky

A great way to prevent TypeScript compilation errors from bringing down your CI pipelines is to introduce a type check before you commit your .ts file changes.

If you've worked with Git Hooks before, you'll probably know that one of the best combinations for running pre-commit checks is husky and lint-staged.

Together, these two packages allow you to tap into the relevant Git hook and run commands such as linting on staged files only. It saves a bunch of debugging time by fixing preventable errors sooner in the development process.

As a separate step, if you want to check for TypeScript type errors (note: this is different to syntax errors which ESLint picks up and fixes for you), you would typically run a command in the CLI such as npx tsc --noEmit to compile the TypeScript and highlight any type errors to address.

Now, the best case scenario here is that you simply pop the above TypeScript command into your lint-staged config along with anything else e.g. ESLint, and you're good to go!

Oh no, it doesn't quite work as expected. The error message that you may come across looks something like this:

Option 'project' cannot be mixed with source files on a command line.
Enter fullscreen mode Exit fullscreen mode

The issue I found - and at the time of writing, it is still being discussed - is that lint-staged would pass each staged file to the npx tsc command like npx tsc --noEmit file1.ts file2.ts and that causes TypeScript to simply ignore your tsconfig.json.

Super frustrating!

Fear not however, as there is an extremely helpful tool that runs tsc on specific files without ignoring tsconfig.json and it's called tsc-files. As the tool's author points out:

I wanted to type-check only the staged files with lint-staged.

Perfect for my use case. So, after a quick look at the docs, it was as simple as updating the lint-staged config in my package.json file to use the tsc-files package:

{
  "husky": {
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "**/*.ts": "tsc-files --noEmit"
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Now I am able to run a TypeScript type check on all my staged files using a pre-commit hook.

Tip: use the --pretty flag in the tsc command to add some formatting and colour to your type errors.

If you have any questions on this setup or have tried different approaches, feel free to comment below or start up a convo over on Twitter.

Thanks for reading 👋

Top comments (10)

Collapse
 
fatedx profile image
Stephen Baker • Edited

@martinsjastad, I read your article a few months ago and was all hyped on tsc-files. I set it up and used it in Production until today when I came to the hard conclusion that it simply does not help identify errors in other files.

So, for example, if you change the way an export works in FileA and commit your code, any files importing FileA will likely all be broken, and you will not be notified of the breakage until you deploy it.

It is for this reason that I instead added a Husky pre-commit hook to my project that executes npx tsc on commit and fails the commit if any errors are found.

I hope this helps someone. :)

Collapse
 
thiagocolebrusco profile image
thiagocolebrusco

I was looking for something like lint-staged but then I thought exactly the same thing. It is not helpful for validating TS.

Collapse
 
luckydevboy profile image
Mohammad Reza Ghasemi

Can you explain how did you do that?

Collapse
 
skathuria29 profile image
Saloni Kathuria

Hello @fatedx so by this, your pre commit hook runs on all files be it staged or unstaged ? In order to catch that import error.

Collapse
 
mrms profile image
Martin Sjåstad

Would this check the types of other files affected by changes to the staged files?

Collapse
 
samueldjones profile image
Sam Jones

Hmm I don't think it would as it specifically looks at staged - worth investigating though!

Collapse
 
amiceli profile image
amiceli

@samueldjones you made my day !
I added it to lint-staged config (custom d.ts file for import with files like .vue ;) ) and it works !
Really thanks you.

Collapse
 
omigtito profile image
Miguel Machado Pacheco

Thanks! Exactly what i was looking for!

Collapse
 
thomassalty profile image
Thomas Soos

What if there are let's say 10 staged *.ts files and all of them have type errors? Will this solution type check all 10 files or throws an error after the first one and skips the rest?

Collapse
 
nanacti profile image
Nana-Cti

My solution

 "lint-staged": {
    "**/*.ts": "bash -c \"tsc $* --noEmit\""
  }
Enter fullscreen mode Exit fullscreen mode