Skip to content

TypeScript 2.0 change in IterableResult<T> makes implementing iterators harder #11375

Closed
@BurtHarris

Description

@BurtHarris

TypeScript Version: 2.0.3
The definition in lib.es6.d.ts of IteratorResult (removing the ? after value) seems to have broken existing Iterator implementations, and is particularly troublesome with strict null checking enabled. See http://stackoverflow.com/questions/39813087/why-did-typescript-2-0-change-iteratorresultk for more details.

Code
A short version:

export interface JavaIterator<E> {
    hasNext(): boolean;
    next(): E;
    remove(): void;
}
...
class IterableAdapter<T> implements Iterable<T>, IterableIterator<T> {
    private _iterator: JavaIterator<T>
    constructor(private collection: JavaCollection<T>){}

    [Symbol.iterator]() { this._iterator = this.collection.iterator(); return this;}

    next(): IteratorResult<T> {
        if (!this._iterator.hasNext()) return { done: true }; // Error on this line
        return {done: false, value: this._iterator.next()}
    }
}

this version works

class IterableAdapter<T> implements Iterable<T>, IterableIterator<T> {
    private _iterator: JavaIterator<T>
    constructor(private collection: JavaCollection<T>){}

    [Symbol.iterator]() { this._iterator = this.collection.iterator(); return this;}

    next(): IteratorResult<T> {
        if (!this._iterator.hasNext()) {
            // A bit of a hack needed here needed for strict null checking
            return { done: true, value: undefined } as any as IteratorResult<T>;
        }
        return {done: false, value: this._iterator.next()}
    }
}

original bug

class HashMapKeyIterable<K,V> implements Iterator<K>, IterableIterator<K> {
    private _bucket: HashMapEntry<K,V>[];
    private _index: number;

    constructor( private _buckets : Iterator<HashMapEntry<K,V>[]> ){
        this._bucket = undefined;
        this._index = undefined;
    }

    [Symbol.iterator]() { return this }

    next():  IteratorResult<K> {
        while (true) {
            if (this._bucket) {
                const i = this._index++;
                if (i < this._bucket.length) {
                    let item = this._bucket[i];
                    return {done: false, value: item.key}
                }
            }
            this._index = 0
            let x = this._buckets.next();
            if (x.done) return {done: true}; // Under TS 2.0 this needs to
            this._bucket = x.value;          // return {done: true: value: undefined};
            }
        }
    }

Expected behavior:
Clean compile under TypeScript 2.0

Actual behavior:
Errors reported: TS2322: Type '{ done: true; }' is not assignable to type 'IteratorResult'. Property 'value' is missing in type '{ done: true; }'

Note: with strict null checking on, I seem to need to go further, resorting to

return { done: true, value: undefined } as any as IteratorResult<T>;`

Metadata

Metadata

Assignees

Labels

CommittedThe team has roadmapped this issueFixedA PR has been merged for this issueSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions