TypeScript для… из с индексом / ключом?

158

Как описано здесь, TypeScript представляет цикл foreach:

var someArray = [9, 2, 5];
for (var item of someArray) {
    console.log(item); // 9,2,5
}

Но разве нет индекса / ключа? Я ожидал чего-то вроде:

for (var item, key of someArray) { ... }
Мик
источник

Ответы:

295

.forEach уже имеет эту способность:

const someArray = [9, 2, 5];
someArray.forEach((value, index) => {
    console.log(index); // 0, 1, 2
    console.log(value); // 9, 2, 5
});

Но если вам нужны возможности for...of, вы можете mapиспользовать массив с индексом и значением:

for (const { index, value } of someArray.map((value, index) => ({ index, value }))) {
    console.log(index); // 0, 1, 2
    console.log(value); // 9, 2, 5
}

Это немного длинновато, поэтому можно использовать функцию многократного использования:

function toEntries<T>(a: T[]) {
    return a.map((value, index) => [index, value] as const);
}

for (const [index, value] of toEntries(someArray)) {
    // ..etc..
}

Итерационная версия

Это будет работать при нацеливании на ES3 или ES5, если вы компилируете с параметром --downlevelIterationкомпилятора.

function* toEntries<T>(values: T[] | IterableIterator<T>) {
    let index = 0;
    for (const value of values) {
        yield [index, value] as const;
        index++;
    }
}

Array.prototype.entries () - ES6 +

Если вы можете настроить таргетинг на среды ES6 +, вы можете использовать .entries()метод, описанный в ответе Arnavion .

Дэвид Шеррет
источник
Но TypeScript компилирует "for ... of" в простой "for", имеющий индекс var _i. Таким образом, разработчикам TypeScript было бы легко позволить нам использовать этот _i. См. Пример игровой площадки: bit.ly/1R9SfBR
Mick
2
@Mick, это зависит от цели. При переносе на ES6 этого не происходит. Причина этого дополнительного кода при транспиляции заключается только в том, чтобы заставить код ES6 работать в прошлых версиях.
Дэвид Шеррет
3
Как можно сделать перерыв? в этом forEach?
Жоао Силва
Также хороший ответ stackoverflow.com/questions/34348937/…
Christopher Grigg
@ JoãoSilva вы можете использовать Array.some()и вернуть false на итерации, которую хотите остановить. Это не так ясно или красиво, как a, breakно с ним можно справиться. Лично мне не нравится это, я бы , вероятно , переписать итерацию каким - либо иным образом :) см stackoverflow.com/questions/2641347/...
NEEK
39

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries

for (var [key, item] of someArray.entries()) { ... }

В TS это требует нацеливания на ES2015, поскольку для этого требуется, чтобы среда выполнения поддерживала итераторы , чего нет в среде выполнения ES5. Конечно, вы можете использовать что-то вроде Babel, чтобы вывод работал во время выполнения ES5.

Арнавион
источник
37

«Старый школьный javascript» на помощь (для тех, кто не знаком / не любит функциональное программирование)

for (let i = 0; i < someArray.length ; i++) {
  let item = someArray[i];
}
Сильвен
источник
2
На самом деле я предпочитаю этот ответ. Никаких дополнительных методов только для создания индекса для каждого элемента.
bluegrounds
Спасибо тебеуууууууууууууууууу! Мы этого не знали :)
TSR
14

Вы можете использовать оператор for..in TypeScript для доступа к индексу при работе с коллекциями.

var test = [7,8,9];
for (var i in test) {
   console.log(i + ': ' + test[i]);
} 

Выход:

 0: 7
 1: 8
 2: 9

См. Демонстрацию

Каранвир Канг
источник
Имейте в виду, что «i» - это строка, а не int с циклом for..in. Выполнение арифметической операции с «i» приведет к объединению строк. (i + 1) будет равно «01», например, когда i = 0
Стефан
for..inтакже может дать вам больше, чем вы ожидали, поскольку он также включает все функции, объявленные для объекта. Например:for (var prop in window.document) { console.log(prop); }
Кен Лайон
7

Или другое решение старой школы:

var someArray = [9, 2, 5];
let i = 0;
for (var item of someArray) {
    console.log(item); // 9,2,5
    i++;
}
Галдор
источник