April 10th, 2017

Announcing TypeScript 2.3 RC

Daniel Rosenwasser
Principal Product Manager
The TypeScript 2.3 Release Candidate is here today! This release brings more ECMAScript features, new settings to make starting projects easier, and more.

To get started with the release candidate, you can grab it through NuGet or over npm through

npm install -g typescript@rc

You can also get TypeScript for Visual Studio 2015 (if you have Update 3). Our team is working on supporting Visual Studio 2017 in the near future, with details available on our previous blog post.

Other editor support will be coming with the proper release, but you can follow instructions to enable newer versions of TypeScript in Visual Studio Code and Sublime Text 3.

In this post we’ll take a closer look at the new --strict option along with async generator and iterator support, but to see a more detailed list of our release, check out the TypeScript Roadmap.

The --strict option

By default, TypeScript’s type system is as lenient as possible to allow users to add types gradually. But have you ever started a TypeScript project with all the strictest settings you could think of?

While TypeScript has options for enabling different levels of strictness, it’s very common to start at the strictest settings so that TypeScript can provide the best experience.

The problem with this is that the compiler has grown to have a lot of different options. --noImplicitAny, --strictNullChecks, --noImplicitThis, and --alwaysStrict are just a few of the more common strictness options that you need to remember when starting a new project. Unfortunately if you can’t remember these, it just makes TypeScript harder to use.

That’s why in TypeScript 2.3, we’re introducing the --strict flag. The --strict flag enables these common strictness options implicitly. If you ever need to opt out, you can explicitly turn these options off yourself. For example, a tsconfig.json with all --strict options enabled except for --noImplicitThis would look like the following:

{
    "compilerOptions": {
        "strict": true,
        "noImplicitThis": false
    }
}

In the future --strict may include other strict checks that we believe will benefit all users, but can be manually toggled off by disabling them explicitly (as mentioned above.)

Downlevel generator & iterator support

Prior to TypeScript 2.3, generators were not supported when targeting ES3 & ES5. This stemmed from the fact that support for generators implied that other parts of the language like forof loops could play well with iterators, which wasn’t the case. TypeScript assumed these constructs could only work on arrays when targeting ES3/ES5, and because generalizing the emit would lead to drastic changes in output code. Something as conceptually simple as a forof loop would have to handle cases that might never come up in practice and could add slight overhead.

In TypeScript 2.3, we’ve put the work in for users to start working with generators. The new --downlevelIteration flag gives users a model where emit can stay simple for most users, and those in need of general iterator & generator support can opt in. As a result, TypeScript 2.3 makes it significantly easier to use libraries like redux-saga, where support for generators is expected.

Async generators & iterators

With our support for regular generator & iterator support, TypeScript 2.3 brings support for async generators and async iterators. You can read more about these features on the TC39 proposal, but we’ll try to give a brief explanation and example.

Async iterators are an upcoming ECMAScript feature that allows iterators to produce results asynchronously. They can be cleanly consumed from asynchronous functions with a new construct called async for loops. These have the syntax

for await (let item of items) {
    /*...*/
}

Async generators are generators which can await at any point. They’re declared using a syntax like

async function* asyncGenName() {
    /*...*/
}

Let’s take a quick look at an example that use both of these constructs together.

// Returns a Promise that resolves after a certain amount of time.
function sleep(milliseconds: number) {
    return new Promise<void>(resolve => {
        setTimeout(resolve, milliseconds);
    });
}

// This converts the iterable into an async iterable.
// Each element is yielded back with a delay.
async function* getItemsReallySlowly<T>(items: Iterable<T>) {
    for (const item of items) {
        await sleep(500);
        yield item;
    }
}

async function speakLikeSloth(items: string[]) {
    // Awaits before each iteration until a result is ready.
    for await (const item of getItemsReallySlowly(items)) {
        console.log(item);
    }
}

speakLikeSloth("never gonna give you up never gonna let you down".split(" "))

Keep in mind that our support for async iterators relies on support for Symbol.asyncIterator to exist at runtime. You may need to polyfill Symbol.asyncIterator, which for simple purposes can be as simple as

(Symbol as any).asyncIterator = Symbol.asyncIterator || Symbol.from("Symbol.asyncIterator");

or even

(Symbol as any).asyncIterator = Symbol.asyncIterator || "__@@asyncIterator__";

If you’re using ES5 and earlier, you’ll also need to use the --downlevelIteration flag. Finally, your TypeScript lib option will need to include "esnext".

Enjoy!

Keep an eye out for the full release of TypeScript 2.3 later this month which will have many more features coming.

For our Visual Studio 2017 users: as we mentioned above, we’re working hard to ensure future TypeScript releases will be available for you soon. We apologize for this inconvenience, but can assure you that a solution will be made available.

We appreciate any and all constructive feedback, and welcome you to leave comments below and file issues on GitHub if needed.

Category
TypeScript

Author

Daniel Rosenwasser
Principal Product Manager

Daniel Rosenwasser is the product manager of the TypeScript team. He has a passion for programming languages, compilers, and great developer tooling.

0 comments

Discussion are closed.

'; block.insertAdjacentElement('beforebegin', codeheader); let button = codeheader.querySelector('.copy-button'); button.addEventListener("click", async () => { let blockToCopy = block; await copyCode(blockToCopy, button); }); } }); async function copyCode(blockToCopy, button) { let code = blockToCopy.querySelector("code"); let text = ''; if (code) { text = code.innerText; } else { text = blockToCopy.innerText; } try { await navigator.clipboard.writeText(text); } catch (err) { console.error('Failed to copy:', err); } button.innerText = "Copied"; setTimeout(() => { button.innerHTML = '' + svgCodeIcon + ' Copy'; }, 1400); }