Monday, July 8, 2013

TypeScript as a better JSLint

TypeScript, if you haven't heard of it, is Yet Another JavaScript Transpiler (YAJST). Their marketing pitch:
TypeScript is a language for application - scale JavaScript development. TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any browser. Any host. Any OS. Open Source.
Apart from using the language for its added benefits you can also use the TypeScript Compiler (tsc.exe) as a very powerful and better form of JSLint that can catch "compile time errors" in a language that isn't compiled, in this case JavaScript.


A compiled language like Java, C, C++, or C# benefit from a first round of implicit unit tests which is the compilation of the code. i.e. before deploying the code it's been validated by the compiler and we know that syntactically it is "clean." Of course it may still be very buggy.

JavaScript doesn't have this benefit. We can run unit tests against the JS we write and if not syntactically correct we can catch some of those syntactic errors. However, if we don't have exhaustive, comprehensive and high quality unit tests we won't catch everything. We also can't test for intent.

Here's a trivial JavaScript example that works and is valid but may be a bug:

function getDivisor() {
    return "5";
}

function myTest() {
    console.log(10 / getDivisor());
}


If you run this through the TypeScript Compiler then you'll get this error:

TypeScriptTest.ts(3,17): error TS2112: The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.

JavaScript will execute this code correctly. It coerces the "5" in a string into an int and everything works as expected. However, TypeScript knows that the only type that can be returned by the getDivisor() function is string and by using implicit typing it knows that you can't (or shouldn't) try and divide by a string.

We can fix this by changing getDivisor() to look like this:

function getDivisor() {
    return parseInt("5");
}


Even if you don't use any of the features of TypeScript, your code quality can improve by inserting TypeScript as part of your build process. I'd suggest that you add this immediately after any other code in your system has been compiled and just before you run any unit tests.

As a note, TypeScript will not accept a .js file as an input, it will only accept .ts files. As such you will need to copy your .js files to a temporary location, renamed them to .ts files, run tsc.exe against them and capture the output.

3 comments:

  1. As a comparison I just ran the above with JSHint and it produced no warnings.

    ReplyDelete
  2. FYI: If you open up the typescript compiler source, you can adjust the isTSFile() function to also accept *.js files and not just *.ts files. This way you can run tsc against your source without having to rename your .js files to .ts.

    I've done this a couple times to experiment with how big of a workload it would take to convert over to TypeScript on a project.

    ReplyDelete
  3. Thanks Jason - I was not aware of that.

    ReplyDelete