# TypeScript Iterators and Generators

Iterators and Generators are powerful features in JavaScript (ES6) that allow you to customize how data is traversed. TypeScript adds type safety to these patterns.

## 1. Iterators

An object is an **Iterator** if it knows how to access items from a collection one at a time, while keeping track of its current position within that sequence. It provides a `next()` method that returns `{ value: T, done: boolean }`.

An object is **Iterable** if it has a method keyed by `Symbol.iterator` that returns an Iterator.

### Built-in Iterables
Arrays, Strings, Maps, and Sets are built-in iterables.

```typescript
let numbers = [1, 2, 3];
for (let num of numbers) {
    console.log(num);
}
```

### Custom Iterator
You can implement the `Iterable` interface to make your own objects usable in `for...of` loops.

```typescript
class Counter implements Iterable<number> {
    constructor(public limit: number) {}

    [Symbol.iterator](): Iterator<number> {
        let count = 0;
        let limit = this.limit;
        
        return {
            next(): IteratorResult<number> {
                if (count < limit) {
                    return { done: false, value: ++count };
                } else {
                    return { done: true, value: null as any };
                }
            }
        }
    }
}

let counter = new Counter(3);
for (let i of counter) {
    console.log(i); // 1, 2, 3
}
```

## 2. Generators

Generators provide a much easier way to create iterators. Instead of managing state and implementing `next()` manually, you write a function that can pause execution using `yield`.

### Syntax
Use an asterisk `*` after the `function` keyword.

```typescript
function* simpleGenerator() {
    yield 1;
    yield 2;
    yield 3;
}

let iterator = simpleGenerator();

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
```

## 3. Typing Generators

TypeScript provides the `Generator<T, TReturn, TNext>` generic type.

*   `T`: The type of values yielded by `yield`.
*   `TReturn`: The type of the value returned by `return` (optional, defaults to `void`).
*   `TNext`: The type of the value passed to `next()` (optional, defaults to `unknown`).

```typescript
function* generateId(): Generator<number, string, boolean> {
    let i = 0;
    while (true) {
        // 'reset' captures the value passed to next(val)
        const reset = yield i++; 
        if (reset) {
            i = 0;
        }
        if (i > 10) {
            return "Limit reached";
        }
    }
}

const gen = generateId();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next(true).value); // 0 (reset)
```

## 4. Async Iterators and Generators

You can also iterate over data that comes asynchronously (like streams).

### Async Generators
Use `async function*` and `await` inside.

```typescript
async function* asyncGenerator() {
    let i = 0;
    while (i < 3) {
        await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1s
        yield i++;
    }
}

(async () => {
    for await (const num of asyncGenerator()) {
        console.log(num);
    }
})();
```

[[programming/javascript/typescript/typescript]]