typescript 'string' 不能用于索引类型 '{}'
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/57350092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
'string' can't be used to index type '{}'
提问by Max Tommy Mitschke
I have the following React component that generates an HTML Table from an array of objects. The columns that should be displayed are defined through the tableColumns
property.
我有以下 React 组件,可从对象数组生成 HTML 表。应该显示的列是通过tableColumns
属性定义的。
When looping through items
and displaying the correct columns I have to use the key
property from the tableColumn
object ({item[column.key]}
) but typescript is generating the following error:
当循环items
并显示正确的列时,我必须使用对象 ( ) 中的key
属性,但打字稿生成以下错误:tableColumn
{item[column.key]}
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. No index signature with a parameter of type 'string' was found on type '{}'.
元素隐式具有“any”类型,因为“string”类型的表达式不能用于索引类型“{}”。在类型“{}”上找不到带有“字符串”类型参数的索引签名。
What could I do to fix this? I'm lost
我能做些什么来解决这个问题?我迷路了
How I call the component:
我如何调用组件:
<TableGridView
items={[
{
id: 1,
name: 'John Doe',
email: '[email protected]'
},
{
id: 2,
name: 'Lorem ipsum',
email: '[email protected]',
}
]}
tableColumns={[
{
key: 'id',
label: 'ID',
},
{
key: 'name',
label: 'Name',
}
]}
/>
My Component:
我的组件:
export type TableColumn = {
key: string,
label: string,
};
export type TableGridViewProps = {
items: object[],
tableColumns: TableColumn[]
};
const TableGridView: React.FC<TableGridViewProps> = ({ tableColumns, items }) => {
return (
<table>
<tbody>
{items.map(item => {
return (
<tr>
{tableColumns.map((column, index) => {
return (
<td
key={column.key}
className="lorem ipsum"
>
{item[column.key]} // error thrown here
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
}
回答by Jonas Wilms
items: object[],
Thats just a bad type. Yes, technically it is a JavaScript object. But for Typescript to correctly help you identify mistakes when accessing objects properties, you need to tell it the exact shape of the object. If you type it as object
, typescript cannot help you with that. Instead you could tell it the exact properties and datatypes the object has:
那只是一个坏类型。是的,从技术上讲,它是一个 JavaScript 对象。但是要让 Typescript 在访问对象属性时正确帮助您识别错误,您需要告诉它对象的确切形状。如果您将其键入为object
,则打字稿无法帮助您。相反,您可以告诉它对象具有的确切属性和数据类型:
let assistance: { safe: string } = { safe: 1 /* typescript can now tell this is wrong */ };
assistance.unknown; // typescript can tell this wont really work too
Now in the case that the object can contain any sort of key / value pair, you can at least tell typescript what type the values (and the keys) have, by using an object index type:
现在,如果对象可以包含任何类型的键/值对,您至少可以通过使用对象索引类型告诉打字稿值(和键)的类型:
items: {
[key: string]: number | string,
}[]
That would be the accurate type in the case given.
在给定的情况下,这将是准确的类型。
回答by Lucas Vazquez
Try to change:
尝试改变:
items={[
{}
]}
To:
到:
items=[
{}
]
Is this, the supposed output?
这是假设的输出吗?
1
John Doe
2
Lorem ipsum
I obtain that.
我得到那个。
回答by Alex Mckay
Use Generics
使用泛型
// bad
const _getKeyValue = (key: string) => (obj: object) => obj[key];
// better
const _getKeyValue_ = (key: string) => (obj: Record<string, any>) => obj[key];
// best
const getKeyValue = <T extends object, U extends keyof T>(key: U) => (obj: T) =>
obj[key];
Bad - the reason for the error is the object
type is just an empty object by default. Therefore it isn't possible to use a string
type to index {}
.
不好 - 错误的原因是object
默认情况下类型只是一个空对象。因此不可能使用string
类型来索引{}
。
Better - the reason the error disappears is because now we are telling the compiler the obj
argument will be a collection of string/value (string/any
) pairs. However, we are using the any
type, so we can do better.
更好 - 错误消失的原因是因为现在我们告诉编译器obj
参数将是字符串/值 ( string/any
) 对的集合。但是,我们正在使用该any
类型,因此我们可以做得更好。
Best - T
extends empty object. U
extends the keys of T
. Therefore U
will always exist on T
, therefore it can be used as a look up value.
最佳 -T
扩展空对象。U
扩展T
. 因此U
将始终存在于T
,因此它可以用作查找值。
Here is a full example:
这是一个完整的例子:
I have switched the order of the generics (U extends keyof T
now comes before T extends object
) to highlight that order of generics is not important and you should select an order that makes the most sense for your function.
我已经切换了泛型的顺序(U extends keyof T
现在在前面T extends object
)以强调泛型的顺序并不重要,您应该选择一个对您的函数最有意义的顺序。
const getKeyValue = <U extends keyof T, T extends object>(key: U) => (obj: T) =>
obj[key];
interface User {
name: string;
age: number;
}
const user: User = {
name: "John Smith",
age: 20
};
const getUserName = getKeyValue<keyof User, User>("name")(user);
// => 'John Smith'