TypeScript. Итераторы

Итерируемым (перечисляемым) считается любой объект, который реализует символьное свойство Symbol.iterator. Ряд встроенных в JavaScript типов, таких как Array, String, Map, Set, уже имеют свойство Symbol.iterator и реализуют его, таким образом являясь итерируемыми.

Если у объектов такого типа вызвать функцию Symbol.iterator, то вернется функционал (функция next()), позволяющий перебирать данный объект в цикле. В ответе же на вызов функции next() должен возвращаться объект с двумя свойствами:

  • done - булево значение, показывающее, закончен ли перебор;
  • value - значение следующего итерируемого элемента.

Пример:

let list =  [1, 2, 3];

let listIterator = list[Symbol.iterator]();

console.log(listIterator.next().value); // 1 
console.log(listIterator.next().done); // false 
console.log(listIterator.next().value); // 3 
console.log(listIterator.next().done); // true

Таким образом, можно создавать свои итерируемые объекты и самим реализовывать какой-то свой кастомный перебор таких объектов.

Цикл for..of

Производит перебор элементов итерируемого объекта с использованием функции Symbol.iterator:

let list = [3, 4, 5];

for (let val of list) {
    console.log(val); // 3, 4, 5
}

Отличие for..of от for..in

for..in возвращает список ключей итерируемого объекта, тогда как for..of возвращает список значений его свойств:

let list = [3, 4, 5];

for (let i in list) {
    console.log(i); // 0, 1, 2
}

for (let i of list) {
    console.log(i); // 3, 4, 5
}

Транспилированный код

Если компилятор TypeScript настроен на соответствие требованиям ES3 или ES5, то цикл for..of будет преобразован в следующий код:

for (var _i = 0, list_1 = list; _i < list_1.length; _i++) {
    var i = list_1[_i];
    console.log(i); // 3, 4, 5
}

При этом, если попытаться использовать цикл for..of на объектах, тип которых отличен от Array, даже если эти объекты реализуют Symbol.iterator, TypeScript сообщит об ошибке.