2021-01-25 13:00:04
TypeScript: type X has no index signatureПродовжимо розмову про Advanced Types у TypeScript. Перш ніж переходити до наступних тем, поговоримо про index signature та помилку type '{}' has no index signature.
Коли ми у TS хочемо описати ключі та значення об’єкту, у нас є дві можливості залежно від того, чи ми точно знаємо, які ключі міститиме об’єкт, чи ні (ключі динамічні чи невідомі нам з інших причин). В першому випадку ми, очевидно, описуємо очікувані властивості. А у другому випадку нам на допомогу прийде index signature – опис типів ключів та відповідних значень без вказання конкретних ключів. Є інші можливості (зокрема Mapped Types, про які ми ще поговоримо).
Почнемо знайомство з index signature з назви. До чого тут індекси? Слово index означає “вказівник”, проте в термінах TS
index (into an object) значить "отримувати доступ до властивостей об'єкта за ключем". Нам добре знайомі колекції з числовими індексами (масиви), проте індексом може бути й рядок. Принаймні, так вважає TypeScript
const user = {
name: ‘John’,
age: 20
}
user["name"] // John
user.name // John
Тож, indexing - це доступ за індексом (рядковим, числовим), а index signature - це сигнатура (опис типів) ключів та значень об’єкта, яка буде використана при такому доступі.
Index signature виглядає так:
{ [x: string]: number }
У нашому прикладі x вказує на ключ, string - тип ключа, а number - тип значення.
Тобто, цей тип говорить, що в об’єкті даного типу будь-якому рядковому ключеві відповідає числове значення.
Також ми можемо комбінувати ці два підходи і попросити TypeScript перевірити, що в об’єкті є певні фіксовані властивості. Обмеженням є те, що тип значень в усіх властивостей має бути один.
type StringToBoolean = {
[key: string]: boolean;
isChecked: boolean
} // valid type
Помилка, якщо тип властивості з фіксованим іменем не збігається з типом index signature:
type StringToBooleanOrNumber = {
[key: string]: boolean;
checksCount: number
} // Error: Property 'checksCount' of type 'number' is not assignable to string index type 'boolean'
Через те, що в JS ключі об’єктів і так рядки (окрім символів), то фактично ми описуємо значення. Цей запис не робить припущень щодо наявності чи кількості властивостей в об’єкті: їх може бути багато чи навіть жодної. З index signature слід бути обережними, адже index signature обмежує типи ключів та значень, проте не гарантує, що певний ключ буде у об’єкті. Якщо такий ключ є, то значення за цим ключем буде вказаного типу
В яких випадках нам може знадобитися такий тип?
- Для об’єктів, точні ключі яких невідомі (наприклад, вони динамічні), але ми не хочемо типізувати їх як any.
- Другий приклад менш очевидний: якщо ви перебиратимете типізований об’єкт через Object.keys, ви можете здивуватися, адже TypeScript скаже, що тип ключа - рядок, а не поєднання усіх відомих ключів. Як виходить, що TypeScript не може розібрати ключі? Це рішення прийняте свідомо, про його мотивацію можна почитати тут
https://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208
Тож якщо ви вирішите перебирати ключі з Object.keys, TypeScript змусить вас надати index signature.
То що означає помилка type X has no index signature?Компілятор каже “Це об’єкт, для якого ти не вказав усі ключі, тому може такий ключ в ньому і є, але я не знаю, якого типу його значення. Скажи мені".
Наступного разу поговоримо про спосіб отримати тип усіх ключів у об’єкті - оператор keyof.
1.1K viewsAnastasiya Mashoshyna, edited 10:00