Avatar ·

Как получить индекс элемента в цикле for...of в TypeScript?

Всем привет! Я только начал изучать TypeScript и столкнулся с проблемой при работе с циклами. Раньше в JavaScript я часто использовал обычный цикл `for (let i = 0; i < arr.length; i++)`, чтобы получить и элемент, и его индекс. Но в TypeScript мне посоветовали использовать `for...of`, так как он более читаемый и современный. Проблема в том, что в `for...of` я получаю только значение элемента, но не его индекс. Например, у меня есть массив строк: ```typescript const fruits: string[] = ['apple', 'banana', 'orange']; ``` Я хочу вывести каждый элемент вместе с его номером: ``` 0: apple 1: banana 2: orange ``` С обычным циклом `for` это делается легко, но с `for...of` у меня не получается. Я пробовал использовать `.entries()`, но не уверен, что это правильно в TypeScript. Может быть, есть какой-то встроенный способ или лучшая практика? Подскажите, пожалуйста, как правильно получить индекс в `for...of` в TypeScript, чтобы код был и красивым, и типобезопасным. Заранее спасибо! <<>>

Использование метода entries() вместе с деструктуризацией

В TypeScript (как и в современном JavaScript) лучший способ получить индекс в цикле for...of — это использовать метод массива .entries(). Он возвращает итератор, который при каждой итерации даёт пару [индекс, значение]. С помощью деструктуризации вы можете красиво разделить эти значения.

const fruits: string[] = ['apple', 'banana', 'orange'];

for (const [index, fruit] of fruits.entries()) {
    console.log(`${index}: ${fruit}`);
}
// Вывод:
// 0: apple
// 1: banana
// 2: orange

Как это работает

  • Метод .entries() — возвращает новый итератор, который содержит пары ключ/значение для каждого индекса в массиве. Для массивов "ключ" — это числовой индекс.
  • Деструктуризация массива — const [index, fruit] позволяет сразу извлечь первое значение (индекс) в переменную index, а второе (значение) — в fruit.
  • TypeScript и типы — TypeScript автоматически выводит типы: index будет иметь тип number, а fruit — string (так как массив объявлен как string[]). Никаких дополнительных аннотаций не требуется.

Почему это лучше альтернатив

  • Читаемость — код компактный и понятный.
  • Типобезопасность — TypeScript гарантирует, что вы не перепутаете индекс и значение.
  • Производительность — метод .entries() не создаёт новый массив, он возвращает итератор, который работает "лениво". Это эффективно для больших массивов.
  • Стандарт — это подход, рекомендованный в официальной документации TypeScript и JavaScript.

Дополнительные примеры

Вы можете использовать этот паттерн с любыми итерируемыми объектами, не только с массивами:

// С Map
const map = new Map<string, number>([['a', 1], ['b', 2]]);
for (const [key, value] of map.entries()) {
    console.log(key, value);
}

// С Set (здесь индекс — это сам элемент, но entries() вернёт [value, value])
const set = new Set<number>([10, 20, 30]);
for (const [index, value] of set.entries()) {
    console.log(index, value); // index === value для Set
}

Если вам нужен только индекс (без значения)

Можно использовать .keys():

for (const index of fruits.keys()) {
    console.log(index); // 0, 1, 2
}

Но на практике чаще всего нужны оба значения, поэтому .entries() — универсальное решение.

<<>>

Альтернативный подход: использование метода forEach

Если вы не принципиально хотите использовать именно for...of, то в TypeScript можно применить метод массива forEach. Он принимает колбэк с тремя параметрами: элемент, индекс и сам массив.

const fruits: string[] = ['apple', 'banana', 'orange'];

fruits.forEach((fruit, index) => {
    console.log(`${index}: ${fruit}`);
});

Плюсы:

  • Очень лаконично и читаемо.
  • Индекс сразу доступен как второй параметр.
  • TypeScript корректно выводит типы: fruit: string, index: number.

Минусы:

  • Нельзя использовать break или continue для досрочного выхода из цикла (только через исключение или внешний флаг).
  • Нет поддержки await внутри колбэка (если нужна асинхронная обработка, придётся использовать for...of с .entries()).

Если вам не нужен досрочный выход и асинхронность, forEach — отличная альтернатива, особенно когда код пишется в функциональном стиле.