Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

typescript Symbol.iterator

I'm trying to create a custom iterable.

here is a simplified example of my code:

class SortedArray {
    *[Symbol.iterator]() {
        yield 1;
        yield 2;
        yield 3;
        return 4;
    }
}
const testingIterables = new SortedArray();
for(let item of testingIterables as any) { // i have to cast it as any or it won't compile
    console.log(item);
}

This code will run correctly on ES6 but with TypeScript it will compile and not print the iterable values.

Is this a bug in TypeScript or am I missing something?

Thanks

like image 439
Yariv Katz Avatar asked Feb 02 '18 20:02

Yariv Katz


People also ask

What is a symbol iterator method?

Symbol. iterator is the protocol that makes native objects like Array , Set , and Map iterable by providing a hook into language features like for…of loops and the spread operator. The most obvious use case is in creating new, iterable data structures that are not provided by the language, like a Linked List.

What is IterableIterator?

It's explained in detail here: " IterableIterator is an interface defined by TypeScript that combines the contracts of Iterables and Iterator into one. This is because, in some cases, it makes sense to have the Iterable as an Iterator itself, removing the need to have an external class that serves as the iterator."

How do I loop a list in TypeScript?

TypeScript includes the for...of loop to iterate and access elements of an array, list, or tuple collection. The for...of loop returns elements from a collection e.g. array, list or tuple, and so, there is no need to use the traditional for loop shown above.


1 Answers

It isn't a bug. It depends on your target.

TypeScript made a (terrible, in my opinion) design decision that if you transpile TS for..of to ES5 or ES3, it emits a normal for (var i; i < testingIterables.length; i++) loop.

For that reason, for targets ES5 and ES3, only arrays and strings are allowed in for..of loops.

There are several options to remedy this:

  • If your TypeScript is over 2.3, you can set the downlevelIteration flag to true, this will cause TypeScript to compile iterator correctly, but it means you must have a Symbol.iterator polyfill in runtime for non-supporting browsers, else you risk runtime errors in unexpected places for those browsers.
  • Select a higher target, ES2015 or higher would work. You can then transpile further down with the use of Babel (you'll also need a runtime polyfill to make Symbols work)
  • Unwrap the iterator yourself with the use of while and calls to testingIterables.next().
like image 59
Madara's Ghost Avatar answered Sep 21 '22 12:09

Madara's Ghost