An object can work with for...of when it provides an iterator.

custom iterable A custom iterable implements `Symbol.iterator` and returns an iterator with a `next` method.

Custom Iterable Objects

endValue
custom.ts
Replay: real traced execution (multi-file project)
class NumberRange implements Iterable<number> {
    start: number;
    end: number;

    constructor(start: number, end: number) {
        this.start = start;
        this.end = end;
    }

    [Symbol.iterator](): Iterator<number> {
        let current: number = this.start;
        const last: number = this.end;
        return {
            next(): IteratorResult<number> {
                if (current <= last) {
                    const value: number = current;
                    current = current + 1;
                    return { value: value, done: false };
                }
                return { value: 0, done: true };
            },
        };
    }
}

const endValue: number = 3;
const range: NumberRange = new NumberRange(1, endValue);
const visited: number[] = [];

for (const value of range) {
    visited.push(value);
}

console.log(visited.join("-"));
class NumberRange implements Iterable<number> {
    start: number;
    end: number;

    constructor(start: number, end: number) {
        this.start = start;
        this.end = end;
    }

    [Symbol.iterator](): Iterator<number> {
        let current: number = this.start;
        const last: number = this.end;
        return {
            next(): IteratorResult<number> {
                if (current <= last) {
                    const value: number = current;
                    current = current + 1;
                    return { value: value, done: false };
                }
                return { value: 0, done: true };
            },
        };
    }
}

const endValue: number = 2;
const range: NumberRange = new NumberRange(1, endValue);
const visited: number[] = [];

for (const value of range) {
    visited.push(value);
}

console.log(visited.join("-"));
class NumberRange implements Iterable<number> {
    start: number;
    end: number;

    constructor(start: number, end: number) {
        this.start = start;
        this.end = end;
    }

    [Symbol.iterator](): Iterator<number> {
        let current: number = this.start;
        const last: number = this.end;
        return {
            next(): IteratorResult<number> {
                if (current <= last) {
                    const value: number = current;
                    current = current + 1;
                    return { value: value, done: false };
                }
                return { value: 0, done: true };
            },
        };
    }
}

const endValue: number = 4;
const range: NumberRange = new NumberRange(1, endValue);
const visited: number[] = [];

for (const value of range) {
    visited.push(value);
}

console.log(visited.join("-"));
  1. endValue ← 3, this.start ← 1, this.end ← 3, range ← [object Object]

    5    constructor(start: number, end: number) {6        this.start = start1;7        this.end = end3;8    }910    [Symbol.iterator](): Iterator<number> {11        let current: number = this.start;12        const last: number = this.end;13        return {14            next(): IteratorResult<number> {15                if (current <= last) {16                    const value: number = current;17                    current = current + 1;18                    return { value: value, done: false };19                }20                return { value: 0, done: true };21            },22        };23    }24}2526const endValue→ 3: number = 3;  //@endValue=2, 427const range→ [object Object]: NumberRange = new NumberRange(1, endValue3);28const visited→ (empty): number[] = [];
    values this step1this.start3this.end
  2. current ← 1, this.start ← 1, last ← 3, this.end ← 3

    7    this.end = end;8}910[Symbol.iterator](): Iterator<number> {11    let current→ 1: number = this.start→ 1;12    const last→ 3: number = this.end→ 3;13    return {14        next(): IteratorResult<number> {15            if (current <= last) {16                const value: number = current;17                current = current + 1;18                return { value: value, done: false };19            }20            return { value: 0, done: true };21        },22    };23}
  3. visited ← 1,2,3

    30for (const value of range) {31    visited.push(value3);32}3334console.log(visited1,2,3.join("-"));
    output1-2-3
  1. endValue ← 2, this.start ← 1, this.end ← 2, range ← [object Object]

    5    constructor(start: number, end: number) {6        this.start = start1;7        this.end = end2;8    }910    [Symbol.iterator](): Iterator<number> {11        let current: number = this.start;12        const last: number = this.end;13        return {14            next(): IteratorResult<number> {15                if (current <= last) {16                    const value: number = current;17                    current = current + 1;18                    return { value: value, done: false };19                }20                return { value: 0, done: true };21            },22        };23    }24}2526const endValue→ 2: number = 2;27const range→ [object Object]: NumberRange = new NumberRange(1, endValue2);28const visited→ (empty): number[] = [];
    values this step1this.start2this.end
  2. current ← 1, this.start ← 1, last ← 2, this.end ← 2

    7    this.end = end;8}910[Symbol.iterator](): Iterator<number> {11    let current→ 1: number = this.start→ 1;12    const last→ 2: number = this.end→ 2;13    return {14        next(): IteratorResult<number> {15            if (current <= last) {16                const value: number = current;17                current = current + 1;18                return { value: value, done: false };19            }20            return { value: 0, done: true };21        },22    };23}
  3. visited ← 1,2

    30for (const value of range) {31    visited.push(value2);32}3334console.log(visited1,2.join("-"));
    output1-2
  1. endValue ← 4, this.start ← 1, this.end ← 4, range ← [object Object]

    5    constructor(start: number, end: number) {6        this.start = start1;7        this.end = end4;8    }910    [Symbol.iterator](): Iterator<number> {11        let current: number = this.start;12        const last: number = this.end;13        return {14            next(): IteratorResult<number> {15                if (current <= last) {16                    const value: number = current;17                    current = current + 1;18                    return { value: value, done: false };19                }20                return { value: 0, done: true };21            },22        };23    }24}2526const endValue→ 4: number = 4;27const range→ [object Object]: NumberRange = new NumberRange(1, endValue4);28const visited→ (empty): number[] = [];
    values this step1this.start4this.end
  2. current ← 1, this.start ← 1, last ← 4, this.end ← 4

    7    this.end = end;8}910[Symbol.iterator](): Iterator<number> {11    let current→ 1: number = this.start→ 1;12    const last→ 4: number = this.end→ 4;13    return {14        next(): IteratorResult<number> {15            if (current <= last) {16                const value: number = current;17                current = current + 1;18                return { value: value, done: false };19            }20            return { value: 0, done: true };21        },22    };23}
  3. visited ← 1,2,3,4

    30for (const value of range) {31    visited.push(value4);32}3334console.log(visited1,2,3,4.join("-"));
    output1-2-3-4