Ошибка TypeScript: No index signature with a parameter of type 'string' — как исправить?
Причина ошибки
Ошибка возникает из-за того, что TypeScript строго проверяет типы при доступе к свойствам объекта через квадратные скобки. Когда вы пишете myObj[key], TypeScript видит, что key имеет тип string, и проверяет, есть ли у объекта myObj индексная сигнатура, которая принимает строку. По умолчанию объект { "A": string } такой сигнатуры не имеет — он знает только о конкретном ключе "A".
Решение 1: Индексная сигнатура (для словарей)
Если ваш объект предназначен для хранения данных с динамическими ключами (как словарь), добавьте индексную сигнатуру в тип:
// Явное указание типа с индексной сигнатурой
const myObj: { [key: string]: string } = { "A": "Hello" };
const key = "A";
console.log(myObj[key]); // ✅ Работает
// Или через Record
const myObj2: Record<string, string> = { "A": "Hello" };
console.log(myObj2[key]); // ✅ Тоже работает
Теперь TypeScript знает, что объект может содержать любые строковые ключи, и доступ по переменной key безопасен.
Решение 2: Сужение типа ключа (для фиксированных наборов)
Если у вас объект с известным набором ключей, но ключ приходит извне, используйте as или проверку:
const myObj = { "A": "Hello", "B": "World" };
const key: string = "A"; // пришло из API
// Вариант 1: утверждение типа (type assertion)
console.log(myObj[key as keyof typeof myObj]); // ✅
// Вариант 2: проверка наличия ключа (type guard)
if (key in myObj) {
console.log(myObj[key]); // ✅ TypeScript понимает, что ключ существует
}
// Вариант 3: кастомная функция-проверка
function isValidKey(key: string): key is keyof typeof myObj {
return key in myObj;
}
if (isValidKey(key)) {
console.log(myObj[key]); // ✅
}
Решение 3: Использование Map (для полной динамики)
Если ключи полностью динамические и их много, лучше использовать Map:
const myMap = new Map<string, string>();
myMap.set("A", "Hello");
const key = "A";
console.log(myMap.get(key)); // ✅ Без ошибок
Почему это происходит?
TypeScript пытается защитить вас от ошибок. Если бы он разрешил доступ по любому строковому ключу, вы могли бы случайно обратиться к несуществующему свойству и получить undefined. Индексная сигнатура или проверка ключа — это явное указание компилятору: "я знаю, что делаю, этот ключ точно существует".
Рекомендация
- Для объектов с фиксированными ключами — используйте
keyofс проверкой (inили type guard). - Для словарей с динамическими ключами — добавляйте индексную сигнатуру (
Record<string, T>или{ [key: string]: T }). - Для сложных сценариев — рассмотрите
MapилиProxy.
Выберите подход, который лучше всего соответствует вашей архитектуре. Главное — явно сообщить TypeScript о своих намерениях.
<<Альтернативный подход: дженерики и утилитарные типы
Если вы пишете функцию, которая принимает объект и ключ, можно сделать её универсальной с помощью дженериков:
function getValue<T extends Record<string, any>>(obj: T, key: string): T[keyof T] | undefined {
if (key in obj) {
return obj[key as keyof T];
}
return undefined;
}
const myObj = { "A": "Hello", "B": 42 };
const value = getValue(myObj, "A"); // тип: string | number | undefined
Этот паттерн особенно полезен, когда вы работаете с данными из ненадёжных источников (API, пользовательский ввод). Функция проверяет наличие ключа перед доступом и возвращает undefined для отсутствующих ключей, что предотвращает ошибки в рантайме.
Дополнение: as const для точных литералов
Если вы знаете точные ключи на этапе компиляции, используйте as const:
const myObj = { "A": "Hello" } as const;
type Keys = keyof typeof myObj; // "A"
const key: Keys = "A"; // теперь key имеет тип "A", а не string
console.log(myObj[key]); // ✅ Без ошибок
Этот подход даёт максимальную безопасность типов, но требует, чтобы ключи были известны заранее.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги