Как правильно перебирать (итерировать) Map в TypeScript? Все способы и примеры
Полный гайд по итерации Map в TypeScript
Отличный вопрос! Map в TypeScript (и JavaScript) — это итерируемая коллекция, но с некоторыми особенностями. Давайте разберём все способы перебора с правильной типизацией.
1. Базовая итерация через for...of
Map по умолчанию итерируется по записям (entries). Каждый элемент — это массив [key, value]. TypeScript автоматически выводит тип кортежа:
const userScores = new Map<string, number>([
['Alice', 95],
['Bob', 87]
]);
// Простая итерация — entry имеет тип [string, number]
for (const entry of userScores) {
console.log(entry[0], entry[1]); // Alice 95, Bob 87
}
// Лучший вариант — деструктуризация
for (const [key, value] of userScores) {
console.log(`${key}: ${value}`);
}
2. Использование .entries()
Метод .entries() возвращает тот же самый итератор, что и for...of по умолчанию. Разницы нет:
// Полностью эквивалентно предыдущему примеру
for (const [key, value] of userScores.entries()) {
console.log(key, value);
}
3. Итерация только по ключам (.keys()) или значениям (.values())
Если вам нужны только ключи или только значения:
// Только ключи — тип string
for (const key of userScores.keys()) {
console.log(`Ключ: ${key}`);
}
// Только значения — тип number
for (const value of userScores.values()) {
console.log(`Значение: ${value}`);
}
4. Метод forEach() — функциональный подход
У Map есть встроенный метод forEach, который принимает callback с тремя параметрами (значение, ключ, сам Map):
userScores.forEach((value, key) => {
console.log(`${key} набрал ${value} баллов`);
});
// Если нужен доступ к самому Map (третий параметр):
userScores.forEach((value, key, map) => {
console.log(`Размер Map: ${map.size}`);
map.set(key, value + 5); // изменяем значения
});
5. Преобразование в массив
Иногда удобно превратить Map в массив для дальнейшей обработки:
// Массив записей [key, value]
const entriesArray = Array.from(userScores);
// или
const entriesArray2 = [...userScores];
// Массив только ключей
const keysArray = [...userScores.keys()];
// Массив только значений
const valuesArray = [...userScores.values()];
// Пример с filter
const highScorers = [...userScores].filter(([_, score]) => score > 90);
console.log(highScorers); // [['Alice', 95], ['Charlie', 92]]
6. Важные моменты по типам
TypeScript строго следит за типами при итерации:
const mixedMap = new Map<number, string | boolean>();
mixedMap.set(1, 'hello');
mixedMap.set(2, true);
// TypeScript знает: key — number, value — string | boolean
for (const [key, value] of mixedMap) {
if (typeof value === 'string') {
console.log(value.toUpperCase()); // Без ошибок
}
}
7. Когда что использовать?
for...ofс деструктуризацией — самый читаемый и типизированный способ для базового перебораforEach— когда нужен функциональный стиль или доступ к самому Map.keys()/.values()— если нужна только одна из составляющих- Spread-оператор — для преобразования в массив и цепочек методов (
map,filter,reduce)
Надеюсь, теперь всё стало понятно! Map в TypeScript — мощный инструмент, а правильная итерация делает работу с ним удобной и безопасной.
<<Альтернативный подход: итерация через Iterator и Symbol.iterator
Если вы хотите глубже понять, как работает итерация в TypeScript, можно использовать протокол итератора напрямую. Это особенно полезно, когда нужно вручную управлять процессом перебора или реализовать ленивую итерацию.
const map = new Map<string, number>([
['a', 1],
['b', 2],
['c', 3]
]);
// Получаем итератор вручную
const iterator = map[Symbol.iterator]();
// Ручной перебор
let result = iterator.next();
while (!result.done) {
const [key, value] = result.value;
console.log(key, value);
result = iterator.next();
}
// Или более кратко с деструктуризацией
for (let [key, value] of map) {
// Можно прервать цикл досрочно
if (key === 'b') break;
console.log(key, value);
}
Когда это может пригодиться?
- Реализация кастомных коллекций, совместимых с
for...of - Ленивая генерация данных (например, бесконечные последовательности)
- Тонкая настройка поведения итерации (пропуск элементов, изменение порядка)
Однако в повседневной работе достаточно использовать for...of или forEach, описанные в основном ответе. Прямая работа с итератором — это уже уровень "продвинутого" использования.
Ответов пока нет.
Войдите чтобы оставить ответ