Бесплатный курс по TypeScript. Зарегистрируйтесь для отслеживания прогресса →

TypeScript: Динамические ключи (Index Signature)

В JavaScript как ключи в объектах мы можем использовать строки, числа и символы. Ровно такие же ограничения TypeScript накладывает на свои объектные типы, а нам предстоит научиться с ними работать.

В ходе курса мы уже работали с объектными типами и с интерфейсами, в которых имена полей заданы заранее. Давайте теперь познакомимся с синтакисом для динамических ключей:

type dynamicKeysObject = {
  [key: string | number | symbol]: unknown;
};

Здесь мы объявили объектный тип dynamicKeysObject, в котором ключем может служить любой тип из доступных типов данных key: string | number | symbol. Попробуем указать такой тип для переменной:

const obj: dynamicFieldObject = {
  name: 'John',
  age: 30,
  0: 'zero',
  [Symbol('secret')]: 'symbol',
};

Динамические ключи можно также использовать совместно с указанными явно. Тогда для заданного ключа установится явно указанный тип:

type MyTheme = {
  palette: {
    primary: 'red' | 'green' | 'blue';
    [key: string]: string;
  },
  [key: string]: unknown;
};

const theme = {
  palette: {
    primary: 'red',
  },
  spacing: {
    small: 8,
  },
} satisfies MyTheme;

В примере мы явно указали тип для поля colors, получили кореректную проверку типа с помощью satisfies и при этом оставили достаточно свободы для дальнейшего расширения темы.

Точно такой же синтаксис и поведение у динамических ключей в интерфейсах:

interface MyTheme {
  colors: {
    primary: string;
  };
  [key: string]: unknown;
}

Динамические ключи полезны там, где нам неизвестны все возможные имена полей объекта, но мы хотим ограничить их тип. Или в составнымх типах, например, если мы хотим пометить все поля типа как опциональные:

type Partial<T> = {
  [P in keyof T]?: T[P];
};

Это простой пример имплиментации встроенной в TypeScript утилиты. Здесь мы проходимся по всем ключам типа T и через ? помечаем их как опциональными (T[P] | undefied ! тоже самое). Попробуйте вернуться к этому типу после урока keyof, а также изучить устройство других Utility Types.

Задание

Реализуйте и экспортируйте интерфейс EmployeeSalary, где ключом выступает имя (string), а значением зарплата (number). Также реалтзуйте и экспортируйте функцию buildSalaryStatistics(eployees: EmployeeSalary): SalaryStatistics, которая должна возвращать минимальную (поле min), среднюю (поле avg) и самую высокую (поле max) зарплату.

const employees: EmployeeSalary = {
  mango: 100,
  poly: 50,
  ajax: 150,
};

employees.ironMan = 1000;

buildSalaryStatistics(employees); // { min: 50, max: 1000, avg: 325 }
Упражнение не проходит проверку — что делать? 😶

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

  • Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет 🤨

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя 🤔

Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно 🙄

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.

Полезное


Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics
Если вы столкнулись с трудностями и не знаете, что делать, задайте вопрос в нашем большом и дружном сообществе