TypeScript 2.3
Generators and Iteration for ES5/ES3
First some ES2016 terminology:
Iterators
ES2015 introducedIterator
, which is an object that exposes three methods,next
,return
, andthrow
, as per the following interface:
ts
interfaceIterator<T> {next(value?:any):IteratorResult<T>;return?(value?:any):IteratorResult<T>;throw?(e?:any):IteratorResult<T>;}
This kind of iterator is useful for iterating over synchronously available values, such as the elements of an Array or the keys of a Map.An object that supports iteration is said to be “iterable” if it has aSymbol.iterator
method that returns anIterator
object.
The Iterator protocol also defines the target of some of the ES2015 features likefor..of
and spread operator and the array rest in destructuring assignments.
Generators
ES2015 also introduced “Generators”, which are functions that can be used to yield partial computation results via theIterator
interface and theyield
keyword.Generators can also internally delegate calls to another iterable throughyield *
. For example:
ts
function*f() {yield1;yield* [2,3];}
New--downlevelIteration
Previously generators were only supported if the target is ES6/ES2015 or later.Moreover, constructs that operate on the Iterator protocol, e.g.for..of
were only supported if they operate on arrays for targets below ES6/ES2015.
TypeScript 2.3 adds full support for generators and the Iterator protocol for ES3 and ES5 targets withdownlevelIteration
flag.
WithdownlevelIteration
, the compiler uses new type check and emit behavior that attempts to call a[Symbol.iterator]()
method on the iterated object if it is found, and creates a synthetic array iterator over the object if it is not.
Please note that this requires a native
Symbol.iterator
orSymbol.iterator
shim at runtime for any non-array values.
for..of
statements, Array Destructuring, and Spread elements in Array, Call, and New expressions supportSymbol.iterator
in ES5/E3 if available when usingdownlevelIteration
, but can be used on an Array even if it does not defineSymbol.iterator
at run time or design time.
Async Iteration
TypeScript 2.3 adds support for the async iterators and generators as described by the currentTC39 proposal.
Async iterators
The Async Iteration introduces anAsyncIterator
, which is similar toIterator
.The difference lies in the fact that thenext
,return
, andthrow
methods of anAsyncIterator
return aPromise
for the iteration result, rather than the result itself.This allows the caller to enlist in an asynchronous notification for the time at which theAsyncIterator
has advanced to the point of yielding a value.AnAsyncIterator
has the following shape:
ts
interfaceAsyncIterator<T> {next(value?:any):Promise<IteratorResult<T>>;return?(value?:any):Promise<IteratorResult<T>>;throw?(e?:any):Promise<IteratorResult<T>>;}
An object that supports async iteration is said to be “iterable” if it has aSymbol.asyncIterator
method that returns anAsyncIterator
object.
Async Generators
TheAsync Iteration proposal introduces “Async Generators”, which are async functions that also can be used to yield partial computation results.Async Generators can also delegate calls viayield*
to either an iterable or async iterable:
ts
asyncfunction*g() {yield1;awaitsleep(100);yield* [2,3];yield* (asyncfunction*() {awaitsleep(100);yield4;})();}
As with Generators, Async Generators can only be function declarations, function expressions, or methods of classes or object literals.Arrow functions cannot be Async Generators. Async Generators require a valid, globalPromise
implementation (either native or an ES2015-compatible polyfill), in addition to a validSymbol.asyncIterator
reference (either a native symbol or a shim).
Thefor-await-of
Statement
Finally, ES2015 introduced thefor..of
statement as a means of iterating over an iterable.Similarly, the Async Iteration proposal introduces thefor..await..of
statement to iterate over an async iterable:
ts
asyncfunctionf() {forawait (constxofg()) {console.log(x);}}
Thefor..await..of
statement is only legal within an Async Function or Async Generator.
Caveats
- Keep in mind that our support for async iterators relies on support for
Symbol.asyncIterator
to exist at runtime. You may need to polyfillSymbol.asyncIterator
, which for simple purposes can be as simple as:(Symbol as any).asyncIterator = Symbol.asyncIterator || Symbol.for("Symbol.asyncIterator");
- You also need to include
esnext
in yourlib
option, to get theAsyncIterator
declaration if you do not already have it. - Finally, if your target is ES5 or ES3, you’ll also need to set the
--downlevelIterators
flag.
Generic parameter defaults
TypeScript 2.3 adds support for declaring defaults for generic type parameters.
Example
Consider a function that creates a newHTMLElement
, calling it with no arguments generates aDiv
; you can optionally pass a list of children as well. Previously you would have to define it as:
ts
declarefunctioncreate():Container<HTMLDivElement,HTMLDivElement[]>;declarefunctioncreate<TextendsHTMLElement>(element:T):Container<T,T[]>;declarefunctioncreate<TextendsHTMLElement,UextendsHTMLElement>(element:T,children:U[]):Container<T,U[]>;
With generic parameter defaults we can reduce it to:
ts
declarefunctioncreate<TextendsHTMLElement =HTMLDivElement,U =T[]>(element?:T,children?:U):Container<T,U>;
A generic parameter default follows the following rules:
- A type parameter is deemed optional if it has a default.
- Required type parameters must not follow optional type parameters.
- Default types for a type parameter must satisfy the constraint for the type parameter, if it exists.
- When specifying type arguments, you are only required to specify type arguments for the required type parameters. Unspecified type parameters will resolve to their default types.
- If a default type is specified and inference cannot choose a candidate, the default type is inferred.
- A class or interface declaration that merges with an existing class or interface declaration may introduce a default for an existing type parameter.
- A class or interface declaration that merges with an existing class or interface declaration may introduce a new type parameter as long as it specifies a default.
New--strict
master option
New checks added to TypeScript are often off by default to avoid breaking existing projects.While avoiding breakage is a good thing, this strategy has the drawback of making it increasingly complex to choose the highest level of type safety, and doing so requires explicit opt-in action on every TypeScript release.With thestrict
option it becomes possible to choose maximum type safety with the understanding that additional errors might be reported by newer versions of the compiler as improved type checking features are added.
The newstrict
compiler option represents the recommended setting of a number of type checking options. Specifically, specifyingstrict
corresponds to specifying all of the following options (and may in the future include more options):
In exact terms, thestrict
option sets thedefault value for the compiler options listed above.This means it is still possible to individually control the options.For example,
sh
--strict --noImplicitThisfalse
has the effect of turning on all strict optionsexcept thenoImplicitThis
option. Using this scheme it is possible to express configurations consisting ofall strict options except some explicitly listed options.In other words, it is now possible to default to the highest level of type safety but opt out of certain checks.
Starting with TypeScript 2.3, the defaulttsconfig.json
generated bytsc --init
includes a"strict": true
setting in the"compilerOptions"
section.Thus, new projects started withtsc --init
will by default have the highest level of type safety enabled.
Enhanced--init
output
Along with settingstrict
on by default,tsc --init
has an enhanced output. Defaulttsconfig.json
files generated bytsc --init
now include a set of the common compiler options along with their descriptions commented out.Just un-comment the configuration you like to set to get the desired behavior; we hope the new output simplifies the setting up new projects and keeps configuration files readable as projects grow.
Errors in .js files with--checkJs
By default the TypeScript compiler does not report any errors in .js files including usingallowJs
.With TypeScript 2.3 type-checking errors can also be reported in.js
files withcheckJs
.
You can skip checking some files by adding// @ts-nocheck
comment to them; conversely you can choose to check only a few.js
files by adding// @ts-check
comment to them without settingcheckJs
.You can also ignore errors on specific lines by adding// @ts-ignore
on the preceding line.
.js
files are still checked to ensure that they only include standard ECMAScript features; type annotations are only allowed in.ts
files and are flagged as errors in.js
files.JSDoc comments can be used to add some type information to your JavaScript code, seeJSDoc Support documentation for more details about the supported JSDoc constructs.
SeeType checking JavaScript Files documentation for more details.
The TypeScript docs are an open source project. Help us improve these pagesby sending a Pull Request ❤
Last updated: Jul 14, 2025