如何在 Typescript 中正确键入这样的数组属性迭代器?



以此示例代码为例:

interface Cat {
fur: string
food: string
}
const cats: Array<Cat> = [
{
fur: 'brown',
food: 'fish'
},
{
fur: 'white',
food: 'biscuits'
}
];
interface Cols {
name: string
title: string
}
const cols: Array<Cols> = [
{
name: 'fur',
title: 'Fur colour'
},
{
name: 'food',
title: 'Favourite food'
}
];
cats.map(cat => {
cols.map(col => {
console.log(`${col.title} - ${cat[col.name]}`); // errors here
});
});

cat[col.name]错误:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Cat'.
No index signature with a parameter of type 'string' was found on type 'Cat'.(7053)

我可以通过向cat添加any来抑制该错误,但这违背了重点。键入此内容的正确方法是什么?

这是因为 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 上的概念验证示例。

专业提示:假设您没有显式接口Cat而只有cat对象,您还可以执行以下操作:

// Tell TS that col.name must be a keyof the typeof `cat` object
cat[col.name as keyof typeof cat]

另一种方法是对Cat接口中的属性使用enum,这样您就不必手动强制转换它:因为 TypeScript 可以推断出类型。此方法在不需要手动转换col.name类型的情况下要详细得多(请参阅此处的 Playground 示例):

// 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]}`);
});
});

相关内容

  • 没有找到相关文章

最新更新