typescript 52 lines · 7 steps

Building a lazy iterator pipeline in TypeScript

Generator functions and a chainable wrapper let you compose map, filter, and take without ever building intermediate arrays.

Explained by highlit
1function* map<T, U>(source: Iterable<T>, fn: (value: T, index: number) => U): Generator<U> {
2 let index = 0;
3 for (const value of source) {
4 yield fn(value, index++);
5 }
6}
7 
8function* filter<T>(source: Iterable<T>, predicate: (value: T, index: number) => boolean): Generator<T> {
9 let index = 0;
10 for (const value of source) {
11 if (predicate(value, index++)) {
12 yield value;
13 }
14 }
15}
16 
17function* take<T>(source: Iterable<T>, count: number): Generator<T> {
18 if (count <= 0) return;
19 let taken = 0;
20 for (const value of source) {
21 yield value;
22 if (++taken >= count) return;
23 }
24}
25 
26class Lazy<T> implements Iterable<T> {
27 constructor(private readonly source: Iterable<T>) {}
28 
29 static from<T>(source: Iterable<T>): Lazy<T> {
30 return new Lazy(source);
31 }
32 
33 map<U>(fn: (value: T, index: number) => U): Lazy<U> {
34 return new Lazy(map(this.source, fn));
35 }
36 
37 filter(predicate: (value: T, index: number) => boolean): Lazy<T> {
38 return new Lazy(filter(this.source, predicate));
39 }
40 
41 take(count: number): Lazy<T> {
42 return new Lazy(take(this.source, count));
43 }
44 
45 toArray(): T[] {
46 return [...this.source];
47 }
48 
49 [Symbol.iterator](): Iterator<T> {
50 return this.source[Symbol.iterator]();
51 }
52}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Generators produce values on demand, so chained operations run element-by-element instead of materializing each stage.
  2. 2Wrapping generators in a class with methods that return new instances gives you a fluent, composable pipeline API.
  3. 3Implementing Symbol.iterator makes a class a first-class iterable that spreads, destructures, and loops like native collections.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a lazy iterator pipeline in TypeScript — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code