Announcing TypeScript 2.3

Today we’re excited to bring you our latest release with TypeScript 2.3!

For those who aren’t familiar, TypeScript is a superset of JavaScript that brings users optional static types and solid tooling. Using TypeScript can help avoid painful bugs people commonly run into when writing JavaScript by type-checking your code. TypeScript can actually report issues without you even saving your file, and leverage the type system to help you write code even faster. This leads to a truly awesome editing experience, giving you time to think about and test the things that really matter.

To get started with the latest stable version of 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) as well as Visual Studio 2017 users using Update 2 Preview will be able to get TypeScript by simply installing it from here. To elaborate a bit, this also means that Visual Studio 2017 Update 2 will be able to use any newer version of TypeScript side-by-side with older ones.

For other editors, default support for 2.3 should be coming soon, but you can configure Visual Studio Code and our Sublime Text plugin to pick up whatever version you need.

While our What’s New in TypeScript Page will give the full scoop, let’s dive in to see some of the great new features TypeScript 2.3 brings!

Type checking in JavaScript files with // @ts-check and --checkJs

TypeScript has long had an option for gradually migrating your files from JavaScript to TypeScript using the --allowJs flag; however, one of the common pain-points we heard from JavaScript users was that migrating JavaScript codebases and getting early benefits from TypeScript was difficult. That’s why in TypeScript 2.3, we’re experimenting with a new “soft” form of checking in .js files, which brings many of the advantages of writing TypeScript without actually writing .ts files.

This new checking mode uses comments to specify types on regular JavaScript declarations. Just like in TypeScript, these annotations are completely optional, and inference will usually pick up the slack from there. But in this mode, your code is still runnable and doesn’t need to go through any new transformations.

You can try this all out without even needing to touch your current build tools. If you’ve already got TypeScript installed (npm install -g typescript), getting started is easy! First create a tsconfig.json in your project’s root directory:

{
    "compilerOptions": {
        "noEmit": true,
        "allowJs": true
    },
    "include": [
        "./src/"
    ]
}

Note: We’re assuming our files are in src. Your folder names might be different.

Now all you need to do to type-check a file is to add a comment with // @ts-check to the top. Now run tsc from the same folder as your tsconfig.json and that’s it.

// @ts-check

/**
 * @param {string} input
 */
function foo(input) {
    input.tolowercase()
    //    ~~~~~~~~~~~ Error! Should be toLowerCase
}

We just assumed you didn’t want to bring TypeScript into your build pipeline at all, but TypeScript is very flexible about how you want to set up your project. Maybe you wanted to have all JavaScript files in your project checked with the checkJs flag instead of using // @ts-check comments. Maybe you wanted TypeScript to also compile down your ES2015+ code while checking it. Here’s a tsconfig.json that does just that:

{
    "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "allowJs": true,
        "checkJs": true,
        "outDir": "./lib"
    },
    "include": [
        "./src/**/*"
    ]
}

Note: Since TypeScript is creating new files, we had to set outDir to another folder like lib. That might not be necessary if you use tools like Webpack, Gulp, etc.

Next, you can start using TypeScript declaration files (.d.ts files) for any of your favorite libraries and benefit from any new code you start writing. We think you’ll be especially happy getting code completion and error checking based on these definitions, and chances are, you may’ve already tried it.

This JavaScript checking mode also allows for two other comments in .js files:

  1. // @ts-nocheck to disable a file from being checked when --checkJs is on
  2. // @ts-ignore to ignore errors on the following line.

You might already be thinking of this experience as something similar to linting; however, that doesn’t mean we’re trying to replace your linter! We see this as something complementary that can run side-by-side with existing tools like ESLint on your JavaScript. Each tool can play to its strengths.

If you’re already using TypeScript, we’re sure you have a JavaScript codebase lying around you can turn this on to quickly catch some real bugs in. But if you’re new to TypeScript, we think that this mode will really help show you what TypeScript has to offer without needing to jump straight in or commit.

Language server plugin support

One of TypeScript’s goals is to deliver a state-of-the-art editing experience to the JavaScript world. This experience is something our users have long enjoyed, whether it came to using traditional JavaScript constructs, newer ECMAScript features, or even JSX.

However, in the spirit of separation of concerns, TypeScript avoided special-casing certain content such as templates. This was a problem that we’d discussed deeply with the Angular team – we wanted to be able to deliver the same level of tooling to Angular users for their templates as we did in other parts of their code. That included completions, go-to-definition, error reporting, etc.

After working closely with the Angular team, we’re happy to announce that TypeScript 2.3 officially makes a language server plugin API available. This API allows plugins to augment the regular editing experience that TypeScript already delivers. What all of this means is that you can get an enhanced editing experience for many different workloads.

You can see the progress of Angular’s Visual Studio Code Plugin here which can greatly enhance the experience for Angular users. But importantly, note here is that this is a general API – that means that a plugin can be written for many different types of content. As an example, there’s already a TSLint language server plugin, as well as a TypeScript GraphQL language server plugin! The Vetur plugin has also delivered a better TypeScript and JavaScript editing experience within .vue files for Vue.js through our language server plugin model.

We hope that TypeScript will continue to empower users of different toolsets. If you’re interested in providing an enhanced experience for your users, you can check out this example plugin.

Default type arguments

To explain this feature, let’s take a simplified look at React’s component API. A React component will have props and potentially some state. You could encode this like follows:

class Component<P, S> {
    // ...
}

Here P is the type of props and S is the type of state.

However, much of the time, state is never used in a component. In those cases, we can just write the type as object or {}, but we have to do so explicitly:

class FooComponent extends React.Component<FooProps, object> {
    // ...
}

This may not be surprising. It’s fairly common for APIs to have some concept of default values for information you don’t care about.

Enter default type arguments. Default type arguments allow us to free ourselves from thinking of unused generics. In TypeScript 2.3, we can declare React.Component as follows:

class Component<P, S = object> {
    // ...
}

And now whenever we write Component<FooProps>, we’re implicitly writing Component<FooProps, object>.

Keep in mind that a type parameter’s default isn’t necessarily the same as its constraint (though the default has to be assignable to the constraint).

Generator and async generator support

Previously, TypeScript didn’t support compiling generators or working with iterators. With TypeScript 2.3, it not only supports both, it also brings support for ECMAScript’s new async generators and async iterators.

This is an opt-in feature when using the --downlevelIteration flag. You can read more about this on our RC blog post.

This functionality means TypeScript more thoroughly supports the latest version of ECMAScript when targeting older versions. It also means that TypeScript can now work well with libraries like redux-saga.

Easier startup with better help, richer init, and quicker strictness

Another one of the common pain-points we heard from our users was around the difficulty of getting started in general, and of the discoverability of new options. We had found that people were often unaware that TypeScript could work on JavaScript files, or that it could catch nullability errors. We wanted to make TypeScript more approachable, easier to explore, and more helpful at getting you to the most ideal experience.

First, TypeScript’s --help output has been improved so that options are grouped by their topics, and more involved/less common options are skipped by default. To get a complete list of options, you can type in tsc --help --all.

Second, because users are often unaware of the sorts of options that TypeScript does make available, we’ve decided to take advantage of TypeScript’s --init output so that potential options are explicitly listed out in comments. As an example, tsconfig.json output will look something like the following:

{
  "compilerOptions": {
    /*  Basic  Options */
    "target": "es5",              /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
    "module": "commonjs",         /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
    // "lib": [],                 /* Specify library files to be included in the compilation:  */
    // "allowJs": true,           /* Allow javascript files to be compiled. */
    // "checkJs": true,           /* Report errors in .js files. */
    // "jsx": "preserve",         /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    // "declaration": true,       /* Generates corresponding '.d.ts' file. */
    // "sourceMap": true,         /* Generates corresponding '.map' file. */
    // ...
  }
}

We believe that changing our --init output will make it easier to make changes to your tsconfig.json down the line, and will make it quicker to discover TypeScript’s capabilities.

Finally, we’ve added the --strict flag, which enables the following settings

  • --noImplicitAny
  • --strictNullChecks
  • --noImplicitThis
  • --alwaysStrict (which enforces JavaScript strict mode in all files)

This --strict flag represents a set of flags that the TypeScript team believes will lead to the most optimal developer experience in using the language. In fact, all new projects started with tsc --init will have --strict turned on by default.

Enjoy!

You can read up our full what’s new in TypeScript page on our Wiki, and read our Roadmap to get a deeper look at what we’ve done and what’s coming in the future!

We always appreciate constructive feedback to improve TypeScript however we can. In fact, TypeScript 2.3 was especially driven by feedback from both existing TypeScript users as well as people in the general JavaScript community. If we reached out to you at any point, we’d like to especially thank you for being helpful and willing to make TypeScript a better project for all JavaScript developers.

We hope you enjoy TypeScript 2.3, and we hope that it makes coding even easier for you. If it does, consider dropping us a line in the comments below, or spreading the love on Twitter.

Thanks for reading up on this new release, and happy hacking!