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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:50:54  来源:igfitidea点击:

'string' can't be used to index type '{}'

javascriptreactjstypescript

提问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 tableColumnsproperty.

我有以下 React 组件,可从对象数组生成 HTML 表。应该显示的列是通过tableColumns属性定义的。

When looping through itemsand displaying the correct columns I have to use the keyproperty from the tableColumnobject ({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 objecttype is just an empty object by default. Therefore it isn't possible to use a stringtype to index {}.

不好 - 错误的原因是object默认情况下类型只是一个空对象。因此不可能使用string类型来索引{}

Better - the reason the error disappears is because now we are telling the compiler the objargument will be a collection of string/value (string/any) pairs. However, we are using the anytype, so we can do better.

更好 - 错误消失的原因是因为现在我们告诉编译器obj参数将是字符串/值 ( string/any) 对的集合。但是,我们正在使用该any类型,因此我们可以做得更好。

Best - Textends empty object. Uextends the keys of T. Therefore Uwill 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 Tnow 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'