Announcing TypeScript 2.5

Today we’re happy to bring you TypeScript 2.5! If you’ve read our RC announcement, we’ve got a few new items that we’re proud to highlight!

If you’re not familiar with TypeScript, it’s a typed superset of JavaScript. More simply put, it’s just JavaScript with optional static types. Static types can make it easier to maintain your code by catching bugs early on, making it easier to navigate your projects, giving accurate code completion, and providing handy fixes for when you do make mistakes. By making types optional, you can get the flexibility of plain JavaScript when you need it, all while TypeScript also gives you the option to tighten things up to bring you more type safety. You can learn more about TypeScript on our website.

To start using TypeScript, you can grab it through NuGet or use the following command with npm:

npm install -g typescript

Visual Studio 2015 users (who have Update 3) can install TypeScript 2.5 from here, and Visual Studio 2017 users using version 15.2 or later will be able to get TypeScript by simply installing it from here. Visual Studio 2017 users should be sure to read up on how you can configure your project to target specific versions of TypeScript.

While TypeScript 2.5 will be available for other editors soon, in the meantime you can configure Visual Studio Code and Sublime Text to use a newer version. Other editors may have different approaches to getting TypeScript 2.5 running.

Let’s look at what TypeScript 2.5 brings!

The Extract Function and Extract Method refactorings

Our team is always in search of ways to bring more powerful tools to the TypeScript and JavaScript world. That’s why with TypeScript 2.5 we’ve invested a lot into implementing extract method and extract function: two new refactorings that make complex rewrites trivial.

If you’re using Visual Studio Code, this refactoring will be available in the upcoming release (though you can try it now by using VS Code Insiders releases).

This feature is still fairly new so we expect that there will still be room for improvement, but we’re excited to hear your feedback so we can polish things out.

New quick fixes

We’ve also added a few quick fixes for when TypeScript can guess a little bit at what you meant to write.

One new quick fix will get triggered when you try to use JSDoc-style types in TypeScript. If you’re in the habit of writing types like these, you might be surprised to find out that they’re not valid in TypeScript, but TypeScript is happy to push us in the right direction.

Quick fixes correcting JSDoc-style types to TypeScript-style types.

We’ve also added a quick fix for when you try to reference the type of a property off of another type incorrectly. For example, for the following code

interface Foo {
    bar: number;
}

We might want to declare a variable named xyz whose type is tied to to the type of bar. The correct way to write this would be using an indexed access type:

// Get the type of the property named 'bar' off of 'Foo'.
var xyz: Foo["bar"]

but we might accidentally write var xyz: Foo.bar. TypeScript now can now suggest the correct one in many cases.

A quick fix that corrects `Foo.bar` to `Foo['bar']`.

JSDoc type assertion support in JavaScript files

In TypeScript 2.4, we introduced the ability to get type-checking in JavaScript files so that users can more easily migrate to TypeScript, and have an easier experience with certain more lightweight projects. Taking advantage of this is as simple as adding a // @ts-check at the top of your .js file, or turning on the checkJs flag in yout tsconfig.json‘s compilerOptions.

One thing that it lacked was the ability to “cast” or “assert” the type of an expression. This is important for situations where you know a little more than the type-checker and need to tell it so. To come up with a trivial example, let’s take the following JavaScript code:

// @ts-check

var foo = Math.random() ? "hello" : 100;

foo.toUpperCase();
//  ~~~~~~~~~~~
//  Error! Property 'toUpperCase' does not exist on type 'string | number'.

TypeScript correctly indicates that we might be calling a method that doesn’t exist on numbers. If we wanted to get around this so we can easily get our runtime error, we could write a JSDoc type assertion:

// Works!
var bar = /** @type {string} */ (foo);
bar.toUpperCase();

The syntax is /** @type {YOUR_TYPE_HERE} */ (someParenthesizedExpression).

Keep in mind that if you’ve enabled JavaScript checking on a file, invalid type assertions will still get caught:

var clearlyNumber = /** @type {string} */ (100);
//                      ~~~~~~~~~~~~~~
// Error! Type 'number' cannot be converted to type 'string'.

Optional catch clauses

Thanks to work by Tingan Ho, TypeScript 2.5 brings a new ECMAScript-bound feature for making catch clauses optional. Much of the time, you’ll find yourself writing a try/catch but not really caring about the thrown error. For example:

let contents;
try {
    contents = fs.readFileSync(".config_file").toString('utf8');
}
catch (unusedError) {
    // File might not exist, just fall back to some defaults.
    contents = createDefaultContents();
}

Notice that unusedError is never referenced in the above example. Barring philosophical issues about whether it’s appropriate to ignore the error, we can make our code a little cleaner by taking advantage of the fact that the catch variable is now optional.

let contents;
try {
    contents = fs.readFileSync(".config_file").toString('utf8');
}
catch {
    // File might not exist, just fall back to some defaults.
    contents = createDefaultContents();
}

Deduplicated and redirected packages

When importing using the Node module resolution strategy in TypeScript 2.5, the compiler will now check whether files originate from “identical” packages. If a file originates from a package with a package.json containing the same name and version fields as a previously encountered package, then TypeScript will redirect itself to the top-most package. This helps resolve problems where two packages might contain identical declarations of classes, but which contain private members that cause them to be structurally incompatible.

As a nice bonus, this can also reduce the memory and runtime footprint of the compiler and language service by avoiding loading .d.ts files from duplicate packages.

The --preserveSymlinks compiler flag

TypeScript 2.5 brings the preserveSymlinks flag, which parallels the behavior of the --preserve-symlinks flag in Node.js. This flag also exhibits the opposite behavior to Webpack’s resolve.symlinks option (i.e. setting TypeScript’s preserveSymlinks to true parallels setting Webpack’s resolve.symlinks to false, and vice-versa).

In this mode, references to modules and packages (e.g. imports and /// <reference type="..." /> directives) are all resolved relative to the location of the symbolic link file, rather than relative to the path that the symbolic link resolves to. For a more concrete example, we’ll defer to the documentation on the Node.js website.

Enjoy!

We hope our work in TypeScript 2.5 will make you happier and more productive. If it did, let us know on Twitter with the #iHeartTypeScript hashtag.

Out team appreciates any sort of feedback on how we can improve. Feel free to let us know about any issues you run into or helpful ideas you think might make TypeScript even better to use on our GitHub issue tracker.

As for what’s next, we’ve caught most of what’s new on this blog post, but you can always check out our what’s new in TypeScript page on our wiki for some more details, and keep an eye on our Roadmap that highlights our current plans and is frequently updated.

Thanks for reading and happy hacking!