0

For the below code

class MakeIterable {

    index: number;
    data: number[];

    constructor(data: number[]) {
      this.index = 0;
      this.data = data;
    }

    [Symbol.iterator]() {
      return {
        next: () => {
          if (this.index < this.data.length) {
            return {
                value: this.data[this.index++], 
                done: false
            };
          } else {
            this.index = 0; //If we would like to iterate over this again without forcing manual update of the index
            return {done: true};
          }
        }
      }
    };
}

const itrble: MakeIterable = new MakeIterable([1,2,3,4,5]);

for (const val of itrble) {
    console.log(val);  // expecting '1' '2' '3' '4' '5' 
}

with given configuration,

{

"compilerOptions": {

  "lib": ["es2015", "dom"]
},
"files": [
  "tstut.ts"
]

}


How to resolve below error?

$ tsc --target ES5
tstut.ts(30,19): error TS2495: Type 'MakeIterable' is not an array type or a string type

$ tsc --target ES6
tstut.ts(30,19): error TS2322: Type 'MakeIterable' is not assignable to type 'Iterable<number>'.
  Types of property '[Symbol.iterator]' are incompatible.
    Type '() => { next: () => { value: number; done: boolean; } | { done: boolean; value?: undefined; }; }' is not assignable to type '() => Iterator<number>'.
      Type '{ next: () => { value: number; done: boolean; } | { done: boolean; value?: undefined; }; }' is not assignable to type 'Iterator<number>'.
        Types of property 'next' are incompatible.
          Type '() => { value: number; done: boolean; } | { done: boolean; value?: undefined; }' is not assignable to type '(value?: any) => IteratorResult<number>'.
            Type '{ value: number; done: boolean; } | { done: boolean; value?: undefined; }' is not assignable to type 'IteratorResult<number>'.
              Type '{ done: boolean; value?: undefined; }' is not assignable to type 'IteratorResult<number>'.
                Property 'value' is optional in type '{ done: boolean; value?: undefined; }' but required in type 'IteratorResult<number>'.
overexchange
  • 15,768
  • 30
  • 152
  • 347

1 Answers1

1

TS2495: Type 'MakeIterable' is not an array type or a string type

results from that non-array iterator was used.

for..of and other iteration methods treat iterables as arrays for historical reasons, this results in non-compliant but more succinct output.

downlevelIteration option should be enabled to treat non-array iterables properly.

This isn't necessary for ES6 target. It should work as expected without downlevelIteration.

TS2322: Type 'MakeIterable' is not assignable to type 'Iterable'.

next doesn't always return a value, while it should. It likely should be:

      ...
      } else {
        return {value: undefined, done: true};
      }
      ...
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Is it non-array, because instance has members, `index` & `data`? – overexchange May 13 '18 at 13:03
  • 1
    It is not an array because it's an iterator, not an array. It has `Symbol.iterator` property but no `length` and no numeric index properties. – Estus Flask May 13 '18 at 13:06
  • Btw, you shouldn't do index = 0. Always create a new iterator. See https://stackoverflow.com/questions/23848113/is-it-possible-to-reset-an-ecmascript-6-generator-to-its-initial-state – Estus Flask May 13 '18 at 13:22
  • `['a','b','c']` should be Iterable because it must have property name `[Symbol.iterator]` with value(a zero arguments function that returns an object, conforming to the iterator protocol.). The iterator protocol defines a standard way to produce a sequence of values. `['a','b','c']` should follow that protocol, internally. I did not get you, when you say, `MakeIterable` is non-array iterator. Why Iterable/iterator terms are aligned with array/string? What changes need to be done to make `MakeIterable` look like array iterator? – overexchange May 13 '18 at 13:55
  • Without `downlevelIteration` an iterable should expose `length`, `0`, `1`... props (this is called array-like object) in order to *make it work at run time*, because TS uses `[].slice.call(iterator)` trick to make it iterable in ES5 (this is what `non-compliant but more succinct output` is about). And it should contain [all Array.prototype members](https://github.com/Microsoft/TypeScript/blob/v2.8.3/lib/lib.d.ts#L1117-L1267) *to make it compile* because this is what typing system requires. You can check compiler ES5 output with and without `downlevelIteration` to get some idea. – Estus Flask May 13 '18 at 14:15