Typescript Generic IteratorWrapper

Date: 2025-04-22
function from<T>(iterable: Iterable<T>): IteratorWrapper<T> {
    return new IteratorWrapper(iterable);
}

function* map<T, U>(iter: Iterator<T>, f: (value: T) => U): Generator<U> {
    for (let x of iterableFromIterator(iter)) {
        yield f(x);
    }
}

function* filter<T>(iter: Iterator<T>, f: (value: T) => boolean): Generator<T> {
    for (let x of iterableFromIterator(iter)) {
        if (f(x)) yield x;
    }
}

function* take<T>(iter: Iterator<T>, n: number): Generator<T> {
    let i = 0;
    for (let x of iterableFromIterator(iter)) {
        if (i++ < n) yield x;
        else break;
    }
}

function* skip<T>(iter: Iterator<T>, n: number): Generator<T> {
    let i = 0;
    for (let x of iterableFromIterator(iter)) {
        if (i++ >= n) yield x;
    }
}

function iterableFromIterator<T>(iter: Iterator<T>): Iterable<T> {
    return {
        [Symbol.iterator]() {
            return iter;
        }
    };
}

class IteratorWrapper<T> implements Iterable<T> {
    private iter: Iterator<T>;

    constructor(iterable: Iterable<T>) {
        this.iter = iterable[Symbol.iterator]();
    }

    [Symbol.iterator](): Iterator<T> {
        return this.iter;
    }

    map<U>(f: (value: T) => U): IteratorWrapper<U> {
        return from(map(this.iter, f));
    }

    filter(f: (value: T) => boolean): IteratorWrapper<T> {
        return from(filter(this.iter, f));
    }

    take(n: number): IteratorWrapper<T> {
        return from(take(this.iter, n));
    }

    skip(n: number): IteratorWrapper<T> {
        return from(skip(this.iter, n));
    }

    first(): T | undefined {
        const { value, done } = this.iter.next();
        return done ? undefined : value;
    }

    last(): T | undefined {
        let lastValue: T | undefined = undefined;
        for (let x of iterableFromIterator(this.iter)) {
            lastValue = x;
        }
        return lastValue;
    }

    sum(fn: (arg: T) => number): number {
        let total = 0;
        for (let x of iterableFromIterator(this.iter)) {
            total += fn(x);
        }
        return total;
    }

    min(fn: (arg: T) => number): number | undefined {
        let minValue: number | undefined = undefined;
        for (let x of iterableFromIterator(this.iter)) {
            const val = fn(x);
            if (minValue === undefined || val < minValue) {
                minValue = val;
            }
        }
        return minValue;
    }

    max(fn: (arg: T) => number): number | undefined {
        let maxValue: number | undefined = undefined;
        for (let x of iterableFromIterator(this.iter)) {
            const val = fn(x);
            if (maxValue === undefined || val > maxValue) {
                maxValue = val;
            }
        }
        return maxValue;
    }

    toArray(): T[] {
        return [...iterableFromIterator(this.iter)];
    }
}

Example use:

const numbers = [1, 2, 3, 4, 5];
const result = from(numbers)
    .map(x => x * 2)
    .filter(x => x > 5)
    .take(2)
    .toArray();

console.log(result); // [6, 8]



const values = from([1, 2, 3, 4, 5]);

console.log(values.skip(2).toArray());        // [3, 4, 5]
console.log(from([1, 2, 3]).first());         // 1
console.log(from([1, 2, 3]).last());          // 3
console.log(from([1, 2, 3]).sum(x => x));     // 6
console.log(from([1, 2, 3]).min(x => x));     // 1
console.log(from([1, 2, 3]).max(x => x));     // 3

Generated javascript

"use strict";
function from(iterable) {
    return new IteratorWrapper(iterable);
}
function* map(iter, f) {
    for (let x of iterableFromIterator(iter)) {
        yield f(x);
    }
}
function* filter(iter, f) {
    for (let x of iterableFromIterator(iter)) {
        if (f(x))
            yield x;
    }
}
function* take(iter, n) {
    let i = 0;
    for (let x of iterableFromIterator(iter)) {
        if (i++ < n)
            yield x;
        else
            break;
    }
}
function* skip(iter, n) {
    let i = 0;
    for (let x of iterableFromIterator(iter)) {
        if (i++ >= n)
            yield x;
    }
}

function iterableFromIterator(iter) {
    return {
        [Symbol.iterator]() {
            return iter;
        }
    };
}
class IteratorWrapper {
    constructor(iterable) {
        this.iter = iterable[Symbol.iterator]();
    }
    [Symbol.iterator]() {
        return this.iter;
    }
    map(f) {
        return from(map(this.iter, f));
    }
    filter(f) {
        return from(filter(this.iter, f));
    }
    take(n) {
        return from(take(this.iter, n));
    }
    skip(n) {
        return from(skip(this.iter, n));
    }
    first() {
        const { value, done } = this.iter.next();
        return done ? undefined : value;
    }
    last() {
        let lastValue = undefined;
        for (let x of iterableFromIterator(this.iter)) {
            lastValue = x;
        }
        return lastValue;
    }
    sum(fn) {
        let total = 0;
        for (let x of iterableFromIterator(this.iter)) {
            total += fn(x);
        }
        return total;
    }
    min(fn) {
        let minValue = undefined;
        for (let x of iterableFromIterator(this.iter)) {
            const val = fn(x);
            if (minValue === undefined || val < minValue) {
                minValue = val;
            }
        }
        return minValue;
    }
    max(fn) {
        let maxValue = undefined;
        for (let x of iterableFromIterator(this.iter)) {
            const val = fn(x);
            if (maxValue === undefined || val > maxValue) {
                maxValue = val;
            }
        }
        return maxValue;
    }
    toArray() {
        return [...iterableFromIterator(this.iter)];
    }
}
const numbers = [1, 2, 3, 4, 5];
const result = from(numbers)
    .map(x => x * 2)
    .filter(x => x > 5)
    .take(2)
    .toArray();
console.log(result); // [6, 8]
const values = from([1, 2, 3, 4, 5]);
console.log(values.skip(2).toArray()); // [3, 4, 5]
console.log(from([1, 2, 3]).first()); // 1
console.log(from([1, 2, 3]).last()); // 3
console.log(from([1, 2, 3]).sum(x => x)); // 6
console.log(from([1, 2, 3]).min(x => x)); // 1

94650cookie-checkTypescript Generic IteratorWrapper