Перейти к основному содержимому

Циклы в 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]);
}

Разбор:

  • keystring; для доступа к 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...ofawait внутри тела, 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условие не меняетсяинвариант цикла

Практика

  1. Найдите сумму number[] через for...of.
  2. Постройте Record<string, number> (слово → счётчик) из string[] через цикл.
  3. Отфильтруйте массив в новый без .filter, через for...of и push.
  4. Переберите Map и найдите ключ с максимальным значением.
  5. Перепишите упражнение 3 через filter и сравните типы в IDE.

Смежные статьи