Объекты TypeScript как типы словаря, как в C #

231

У меня есть код JavaScript, который использует объекты в качестве словарей; например, объект "человек" будет содержать некоторые личные данные, отведенные с адреса электронной почты.

var people = {<email> : <some personal data'>};

adding   > "people[<email>] = <data>;" 
getting  > "var data = people[<email>];" 
deleting > "delete people[<email>];"

Можно ли описать это в Typescript? или мне нужно использовать массив?

  • 5
    Старый пост, но обратите внимание, что есть карта ES6
Теги:
object
arrays
dictionary

5 ответов

412
Лучший ответ

Конечно:

var map: { [email: string]: Customer; } = { };
map['[email protected]'] = new Customer(); // OK
map[14] = new Customer(); // Not OK, 14 is not a string
map['[email protected]'] = 'x'; // Not OK, 'x' is not a customer

Вы также можете создать интерфейс, если вы не хотите каждый раз вводить аннотацию этого типа:

interface StringToCustomerMap {
    [email: string]: Customer;
}

var map: StringToCustomerMap = { };
// Equivalent to first line of above
  • 2
    Это полезный способ убедиться, что компилятор ограничивает индексы строками. Интересно. Не похоже, что вы можете указать тип индекса как что-либо кроме строк или целых чисел, но это имеет смысл, поскольку он просто сопоставляется с собственными индексами объектов JS.
  • 4
    Возможно, вы знаете это, но есть и некоторые потенциальные проблемы с этим подходом, большая из которых заключается в том, что нет безопасного и простого способа перебора всех членов. Этот код, например, показывает, что map содержит два члена: (<any> Object.prototype) .something = function () {}; класс Customer {} var map: {[email: string]: Customer; знак равно map ['[email protected] '] = новый клиент (); for (var i in map) {console.log (map [i])}
Показать ещё 9 комментариев
65

Вы можете использовать шаблонные интерфейсы, например:

interface Map<T> {
    [K: string]: T;
}

let dict: Map<number> = {};
dict["one"] = 1;
  • 6
    Обратите внимание, что это противоречит типу карты es6. Лучше, чем другой ответ, потому что ограничение индекса игнорируется.
  • 0
    Как проверить, существует ли ключ в словаре?
Показать ещё 4 комментария
55

В дополнение к использованию объекта, подобного карте, в течение некоторого времени был фактический Map object, который доступен в TypeScript при компиляции на ES6 или при использовании polyfill с ES6 определения типов:

let people = new Map<string, Person>();

Он поддерживает те же функции, что и Object, и многое другое, с немного отличающимся синтаксисом:

// Adding an item (a key-value pair):
people.set("John", { firstName: "John", lastName: "Doe" });

// Checking for the presence of a key:
people.has("John"); // true

// Retrieving a value by a key:
people.get("John").lastName; // "Doe"

// Deleting an item by a key:
people.delete("John");

Это само по себе имеет несколько преимуществ перед использованием объекта, подобного карте, например:

  • Поддержка нестрочных ключей, например. номера или объекты, ни один из которых не поддерживается Object (no, Object не поддерживает числа, преобразует их в строки)
  • Меньше места для ошибок при использовании --noImplicitAny, так как Map всегда имеет тип ключа и тип значения, тогда как у объекта может отсутствовать подпись-подпись
  • Функциональность добавления/удаления элементов (пары ключ-значение) оптимизирована для задачи, в отличие от создания свойств на Object

Кроме того, объект Map предоставляет более мощный и элегантный API для обычных задач, большинство из которых недоступны с помощью простого Object без взлома вспомогательных функций (хотя для некоторых из них требуется полный итератор ES6/iterable polyfill для целей ES5 или ниже):

// Iterate over Map entries:
people.forEach((person, key) => ...);

// Clear the Map:
people.clear();

// Get Map size:
people.size;

// Extract keys into array (in insertion order):
let keys = Array.from(people.keys());

// Extract values into array (in insertion order):
let values = Array.from(people.values());
  • 1
    Это потрясающе! Но, к сожалению, он неправильно сериализован с использованием JSON.stringify() , поэтому его можно использовать, например, для socket.io :(
  • 0
    @Lion - ну да, сериализация Map довольно забавная. Я, например, выполняю преобразование в объекты пары ключ-значение перед сериализацией, а затем обратно (например, объект { key: "John", value: { firstName: "John" } } ).
Показать ещё 1 комментарий
4

Lodash имеет простую реализацию словаря и имеет хорошую поддержку TypeScript

Установите Lodash:

npm install lodash @types/lodash --save

Импорт и использование:

import { Dictionary } from "lodash";
let properties : Dictionary<string> = {
    "key": "value"        
}
console.log(properties["key"])
1

Вы также можете использовать тип записи в машинописном тексте:

export interface nameInterface { 
    propName : Record<string, otherComplexInterface> 
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню