mihaifm / linq

linq.js - LINQ for JavaScript

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unexpected behavior in [Symbol.iterator]

LviatYi opened this issue · comments

I have a type that implements [Symbol.iterator]:

class IteratorTest {
    // This is just a simple replacement for the data structure that needs to be traversed.
    // It may actually be a tree or other data structure implemented by a custom traversal.
    nums: number[] = [1, 2, 3, 4, 5];

    public [Symbol.iterator](): Iterator<number> {
        let idx = 0;
        return {
            next: (): IteratorResult<number> => {
                if (idx < this.nums.length) {
                    return {
                        value: this.nums[idx++],
                        done: false,
                    };
                } else return {
                    value: undefined,
                    done: true,
                };
            },
        };
    }
}

Enumerable returns an empty array when I try to use it like this:

// in linq.d.ts   export function from<T>(obj: Iterator<T>): IEnumerable<T>;
// so I called:
Enumerable.from(et[Symbol.iterator]()).toArray()

The reason is that during the construction of Enumerable.from():

// linq.js
    if (typeof obj != Types.Function) {
        // array or array-like object
        if (typeof obj.length == Types.Number) {
            return new ArrayEnumerable(obj);
        }

        // iterable object
        if (typeof Symbol !== 'undefined' && typeof obj[Symbol.iterator] !== 'undefined') { // use obj as who has [Symbol.iterator]
            return new Enumerable(function () {
                return new IEnumerator(
                    Functions.Blank,
                    function () {
                        var next = obj.next(); // use obj as iterator
                        return (next.done ? false : (this.yieldReturn(next.value)));
                    },
                    Functions.Blank);
            });
        }
    }

I'm not a typescript expert, but I think this code is dealing with Iterator. obj itself is an Iterator, but here we still try to access obj.[Symbol.iterator].
Then it tries to access obj.next() in the iteration, which is no problem because obj as an Iterator contains a next function.

So I had to change my code to this to get it to work properly:

class ETest {
    nums: number[] = [1, 2, 3, 4, 5];

    public [Symbol.iterator](): Iterator<number> {
        let idx = 0;
        return {
            next: (): IteratorResult<number> => {
                if (idx < this.nums.length) {
                    return {
                        value: this.nums[idx++],
                        done: false,
                    };
                } else return {
                    value: undefined,
                    done: true,
                };
            },

            // A useless function just to pass the `typeof obj[Symbol.iterator] !== 'undefined'` predicate
            [Symbol.iterator](): Iterator<number> {
                return {
                    next(...args): IteratorResult<number, any> {
                        return undefined;
                    },
                };
            },
        };
    }
}

Is there anything wrong with my usage? In my opinion, the former should be the correct usage of from<T>(obj: Iterator<T>): IEnumerable<T>

Resolved in version 4.0.3