Циклы в TypeScript
Дальше: Коллекции · Ветвления · Циклы в JavaScript
Циклы в TypeScript не отличаются от JavaScript: те же for, while, for...of. TS добавляет типы элементов при переборе и подсказки в IDE. Подробная теория и edge cases — в циклах JavaScript; здесь — типизация и связь с коллекциями.
Маршрут: ветвления → циклы → коллекции.
Какой цикл выбрать
| Конструкция | Перебирает | Типичный случай |
|---|---|---|
for...of | значения итерируемого | массив, Map, строка |
for с индексом | индекс + доступ по [i] | нужен номер элемента |
for...in | ключи объекта | plain object (осторожно) |
while / do...while | по условию | неизвестное число итераций |
map / filter | — | декларативно, без явного цикла |
В прикладном TS чаще for...of или методы массивов — тип результата выводится автоматически.
for...of и массивы
const names: string[] = ["Ann", "Bob", "Kim"];
for (const name of names) {
console.log(name.toUpperCase());
}
Разбор:
nameвыводится какstring.for...ofне перебирает ключи объекта как произвольные поля — для объекта см.Object.keys/entries.
Классический for с индексом
const items = ["a", "b", "c"];
for (let i = 0; i < items.length; i += 1) {
const current = items[i];
const next = items[i + 1];
console.log(i, current, next);
}
Разбор:
items[i]приnoUncheckedIndexedAccessимеет типstring | undefined— проверяйтеnext.let iограничивает область видимости счётчика.
for...in и объекты
const user = { id: "1", name: "Ann" };
for (const key in user) {
const k = key as keyof typeof user;
console.log(k, user[k]);
}
Разбор:
key—string; для доступа кuser[key]нужно сузить доkeyof typeof user.for...inможет захватить унаследованные перечислимые свойства — для чистых DTO предпочтитеObject.entries.
for (const [key, value] of Object.entries(user)) {
console.log(key, value);
}
while, break, continue
let n = 0;
while (n < 5) {
n += 1;
if (n % 2 === 0) continue;
console.log(n);
}
Разбор:
continueпереходит к следующей итерации;breakвыходит из цикла.- Условие
whileдолжно когда-нибудь стать ложным — иначе бесконечный цикл.
Map и Set
const scores = new Map<string, number>([
["Ann", 90],
["Bob", 85],
]);
for (const [name, score] of scores) {
console.log(`${name}: ${score}`);
}
const tags = new Set(["ts", "js", "ts"]);
for (const tag of tags) {
console.log(tag);
}
Разбор:
Mapитерируется как[key, value]— типы обоих известны.- Подробнее о коллекциях — 19.md.
Циклы vs map / filter
const nums = [1, 2, 3, 4];
const evens = nums.filter((n) => n % 2 === 0);
const doubled = nums.map((n) => n * 2);
| Подход | Плюсы |
|---|---|
map / filter | короче, тип результата выводится |
for...of | await внутри тела, break, сложная логика |
reduce | одна проходка, аккумулятор |
async function loadAll(urls: string[]): Promise<string[]> {
const out: string[] = [];
for (const url of urls) {
const res = await fetch(url);
out.push(await res.text());
}
return out;
}
Разбор:
awaitвнутриmapбезPromise.allдаёт последовательность; параллель — 17.md.
for await...of (асинхронные итерируемые)
type User = { id: string; name: string };
async function* fetchUsers(url: string): AsyncGenerator<User> {
let page = 1;
let hasMore = true;
while (hasMore) {
const res = await fetch(`${url}?page=${page}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const body = (await res.json()) as { items: User[]; hasMore: boolean };
for (const user of body.items) {
yield user;
}
hasMore = body.hasMore;
page += 1;
}
}
async function printAll(): Promise<void> {
for await (const user of fetchUsers("/api/users")) {
console.log(user.name);
}
}
Разбор:
for await...ofждёт каждыйyieldиз async generator (async function*).userв теле цикла типизирован какUser, неunknown.- Полный разбор генераторов — 25.md; async — 17.md.
Частые ошибки
| Ошибка | Причина | Что делать |
|---|---|---|
for...in по массиву | индексы как строки | for...of |
user[key] без keyof | небезопасный индекс | keyof typeof user |
Мутация при for...of | путаница с const элементом | новый массив / map |
await в map без ожидания | Promise[] | for...of или Promise.all |
Бесконечный while | условие не меняется | инвариант цикла |
Практика
- Найдите сумму
number[]черезfor...of. - Постройте
Record<string, number>(слово → счётчик) изstring[]через цикл. - Отфильтруйте массив в новый без
.filter, черезfor...ofиpush. - Переберите
Mapи найдите ключ с максимальным значением. - Перепишите упражнение 3 через
filterи сравните типы в IDE.
Смежные статьи
- Ветвления — условия внутри цикла
- Коллекции —
Map,Set, tuple - Функции — callback в
map - Асинхронность —
for await...of - Справочник — Справочник — составные типы
- Подробно в JS: 23