What It Is
The Iterator pattern walks through a collection without exposing how it is stored. The caller asks only for the next item — whether the data lives in an array, a tree or a database stays private.
TypeScript has this pattern built in. A class that defines a [Symbol.iterator]() method can be walked by for...of, and the easiest way to write that method is a generator: a function marked * that yields values one by one.
Example: Walking a Playlist
The playlist keeps its songs array private. It offers just [Symbol.iterator](), written as a generator — the storage behind it could change completely without breaking any caller.
A generator and for...of
The loop never touches the array inside the playlist; it only asks for the next song, and prints playing: intro, playing: verse, playing: chorus. Swap the array for a linked list or lazy loading, and this loop still works.
Output: TypeScript file and captured output
class Playlist {
private songs: string[]
constructor(songs: string[]) {
this.songs = songs
}
// A generator hands out one song at a time; the array stays private.
*[Symbol.iterator](): Generator<string> {
for (const song of this.songs) {
yield song
}
}
}
const playlist = new Playlist(["intro", "verse", "chorus"])
for (const song of playlist) {
console.log("playing:", song)
}
When to Use It
Use it when the collection's insides must stay private, when walking is nontrivial (trees, pages from an API), or when you need several independent walks at once.
Skip it for plain arrays and Maps in your own code — they are already iterable, so for...of works on them directly.
Pros and Cons
Pros: storage stays private and changeable; each for...of gets its own independent walk; complicated traversal is written once; a generator is lazy — it computes the next value only when asked.
Cons: more code than exposing the array; a live iterator over a changing collection is a classic source of subtle bugs.