TypeScript, переглядаючи словник


184

У своєму коді я маю пару словників (як тут пропонується ), який індексується String. Через те, що це трохи імпровізований тип, мені було цікаво, чи є якісь пропозиції щодо того, як я зможу пройти цикл через кожну клавішу (або значення, все що мені потрібні ключі для будь-якого). Будь-яка допомога вдячна!

myDictionary: { [index: string]: any; } = {};

Чи пробували ви: for (var key in myDictionary) { }? Всередині цикла ви keyотримаєте ключ і myDictionary[key]отримаєте значення
Ян

@Ian Щойно спробував це, схоже, не працює. Немає помилок, але нічого не працює в заяві
ben657

1
@Ian Ah вибачте, якийсь код в іншому місці з цим возився. Це прекрасно працює! Хочете зробити це відповіддю, щоб я міг його вибрати?
ben657

Відповіді:


294

Щоб перейти через ключ / значення, використовуйте for inцикл:

for (let key in myDictionary) {
    let value = myDictionary[key];
    // Use `key` and `value`
}

8
Це взагалі не безпечно; йому потрібен тест hasOwnProperty (як у відповіді Джеймі Старка) або щось інше.
Дон Хетч

20
@DonHatch Це насправді дуже безпечно в цілому. Це не є безпечним у дуже конкретних випадках (наприклад, якщо ви включаєте бібліотеки, які змінюють прототипи неправильно або навмисно змінюють прототипи неправильно). Розробник залежить від того, чи розкривати їх код найімовірнішими-непотрібними чеками
Ian

1
@Ian - Я думаю, що я не використовував би його без додаткових гарантій, оскільки це здається випадковою ситуацією, яка чекає, наприклад, якщо код знайде свій шлях у функції утиліти, а потім хтось передає цю функцію словнику, який не є просто Об'єкт, а то щось із додатковими властивостями. Так, як ви кажете, розробник повинен зважити ймовірність та серйозність такого сценарію. Для мене найменш обтяжливий психічний підхід - це поводитись так, ніби такий сценарій гарантовано трапляється у всіх випадках - менше думати.
Дон Хетч

5
@Ian Проблема полягає в тому, що занадто багато бібліотек, які змінюють прототипи об'єктів. Дуже поганою ідеєю є відстоювання такого типу, коли існують набагато кращі прості альтернативи, такі як Object.keys(target).forEach(key => { let value = target(key); /* Use key, value here */ });. Якщо ви повинні показати цей метод, принаймні згадуйте про ризики та кращі альтернативи для тих, хто ще не знає кращого.
Yona Appletree

8
У нас вже є es6 та TypeScript. Чому проблема написання hasOwnProperty весь час залишається невирішеною? Навіть у 2017 році та з усією увагою до JS. Я так розчарований.
Герман

169

<ES 2017 :

Object.keys(obj).forEach(key => {
  let value = obj[key];
});

> = ES 2017 :

Object.entries(obj).forEach(
  ([key, value]) => console.log(key, value);
);

Це рішення, яке я шукав, оскільки воно дозволить мені сортувати ключі до ітерації
Ендрю

FYI, наразі це не підтримується на майданчику TypeScript.
Seanny123

1
Дивіться тут, як змусити Object.entriesпрацювати в TypeScript
Алекс Клаус

Це ідеально
Піюш Чодхарі

67

Як щодо цього?

for (let [key, value] of Object.entries(obj)) {
    ...
}

1
Це вимагає lib es2017 в tsconfig. Дивіться stackoverflow.com/questions/45422573/…
Stéphane

Це те, що мені потрібно було пропустити помилку Typescript на obj [key] "Немає підпису індексу ...", тому що я чітко встановив свій тип obj як {[key: string]: string} і не хотів використовувати {[key: рядок]: будь-який}. Завдяки цьому я можу просто отримати доступ до "значення". Спасибі
ggedde

І якщо ви хочете , щоб ігнорувати keyвзагалі, просто залиште це поле порожнім: [ , value]. (Завдяки коментарю до цього питання .)
Домінік

50

Є один застереження до ключа / значення циклу, про який згадував Ян. Якщо можливо, об’єкти можуть мати атрибути, приєднані до їх прототипу, і коли ви використовуєте inоператор, ці атрибути будуть включені. Отже, ви хочете переконатися, що ключ є атрибутом вашого примірника, а не прототипом. Старі ІЕ відомі тим, що indexof(v)з'явились як ключові.

for (const key in myDictionary) {
    if (myDictionary.hasOwnProperty(key)) {
        let value = myDictionary[key];
    }
}

2
Не намагаєтеся розділити волоски, але оскільки ми говоримо про тип сценарію, чи не слід використовувати ключ let замість клавіші var? Гарна відповідь дякую.
Лука Дупін

3
Насправді, з поточною версією типу скрипту так keyі valueможе бути const.
Патрік Дежардінс

Краще не викликати hasOwnPropertyчек від цільового об’єкта, а зробити це: ...if (Object.prototype.hasOwnProperty.call(myDictionary, key))...Ще, якщо ви використовуєте eslint з no-prototype-builtinsправилом, він видасть помилку.
sceee

5

Найкоротший спосіб отримати всі значення словника / об’єкта:

Object.keys(dict).map(k => dict[k]);

0

Щоб отримати ключі:

function GetDictionaryKeysAsArray(dict: {[key: string]: string;}): string[] {
  let result: string[] = [];
  Object.keys(dict).map((key) =>
    result.push(key),
  );
  return result;
}

0

Ians Answer - це добре, але вам слід використовувати const, а не пускати ключ, оскільки він ніколи не оновлюється.

for (const key in myDictionary) {
    let value = myDictionary[key];
    // Use `key` and `value`
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.