One of the primary reasons so many JavaScript developers say they now code in TypeScript is that the compile-time checks catch lots of simple mistakes. Oops, that method accepts RegExp , not string — but you found out immediately, not while debugging a mysterious failure at runtime.

You can think of the TypeScript compiler as a linter for the language spec. If you really want to output JavaScript with a string where a RegExp belongs, you can do that, but you’ll get type-check warnings. The set of programs accepted by the compiler are those which are “correct” in some sense. However, the size of this set is always decreasing, because the TypeScript team refines the type system, or adds a new feature like --strictThis . When you enable that flag, even more of your simple mistakes are caught at compile time.

How many bugs are still left in your program that could have been caught this way? When are we done adding --strict* flags?

At Google, we like to make tooling that scales, including scaling our own ability to understand our code. We really want to invest in smarter compiler tooling that finds more bugs with less human inspection. I started a project called Error Prone a few years ago that does this for Java, by extending the diagnostics in the compiler. Today I’m excited to announce we have done the same thing for TypeScript, and we call the tool Tsetse.

Tsetse flies are not very nice bugs, and tsetse starts with “TS”, so Tsetse is the TS bug checker.

Until now, the only way to write your own static analysis checks for TypeScript was to put them in a linter like TSLint. But that isn’t quite what we want, because the linter is used differently from the compiler. The linter produces warnings. Even if you promote some of those to errors, you’d have to run the linter before you debug the program manually, which means running it every time you compile, or in your editor. But not everyone on your team sets up their editor the same way. The one tool we all agree to run before trying out our code is the compiler, so that’s where we want our correctness checks to live. We find bugs in the compiler, and style guide violations in the linter.

At Google, we use the Bazel build tool, and in our Bazel TypeScript compiler, we’ve just introduced the first Tsetse check: CheckReturnValue. This is enabled in version 0.4.0 of @bazel/typescript and is already live for all developers at Google. The code is here.

We also instrument all our internal builds, so the first day the check was enabled, we discovered this code a Googler wrote:

let values: EventValue[] = [];

...

this.values.filter(val => val.label === label);

What does this code do? filter doesn’t modify the object it’s called on, rather it returns a new Array, and here that return value is lost. So the statement has no effect. Our compiler flagged this as a type-check error:

$ bazel build :all

ERROR: /home/user/Project/BUILD:15:1: Compiling TypeScript //:lib failed (Exit 1)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



directory/file.ts(98,7): error TS21222: return value is unused.

See 98 this.values.filter(val => val.label === label);~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~directory/file.ts(98,7): error TS21222: return value is unused.See http://tsetse.info/check-return-value

The developer never even got a chance to run this broken program! We emailed to ask how he felt about this failed build, and the answer was

Hooray!

Thanks for continuously improving Typescript development at Google! :] Cheers!

so that makes us pretty happy. This is only the first new check we’ve added to the compiler. We expect to add many more!

Thanks to Scott Wu (TS@Google intern from two summers ago) and my co-worker Bowen Ni for doing all the work to write the check and integrate it with our compiler!