Это связано с тем, что TypeScript видит col.name
как строку, а интерфейс Cat
содержит только два возможных ключа (ни одна строка в качестве ключей). Теоретически, col.name
может возвращать любую строку, которая отсутствует в качестве ключа в объекте cat
.
Поскольку вы знаете, что col.name
должен быть ключом Cat
интерфейс, вы можете подсказывать TypeScript следующим образом:
// Tell TS that col.name must be a keyof the Cat interface
cat[col.name as keyof Cat]
Следовательно, при таком обновлении кода TypeScript будет распознавать, что col.name
действительно возвращает действительный ключ в интерфейсе Cat
:
cats.map(cat => {
cols.map(col => {
console.log(`${col.title} - ${cat[col.name as keyof Cat]}`);
});
});
См. Пример проверки концепции на TypeScript Playground .
Pro-tip: допустим, у вас нет явного интерфейса Cat
, а есть только cat
объект, вы также можете сделать:
// Tell TS that col.name must be a keyof the typeof `cat` object
cat[col.name as keyof typeof cat]
Альтернативный способ - использовать enum
для свойств в интерфейсе Cat
, поэтому вам не придется вручную бросьте его: так как TypeScript может вывести тип как таковой. Этот метод значительно более многословен на том основании, что не нужно вручную приводить тип col.name
( см. Пример игровой площадки здесь ):
// Declare an enum for properties in `Cat` interface
enum CatProperty {
FUR = 'fur',
FOOD = 'food',
}
Затем при определении массива для ваш cols
, вам нужно будет использовать перечисления:
const cols: Array<Cols> = [
{
name: CatProperty.FUR,
title: 'Fur colour'
}
];
Это должно привести к тому, что TypeScript сможет распознавать, что col.name
должно иметь значение fur | food
, которое существует в Cat
интерфейс, поэтому кастинг не требуется:
cats.map(cat => {
cols.map(col => {
console.log(`${col.title} - ${cat[col.name]}`);
});
});