typescript 元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/57086672/
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
Element implicitly has an 'any' type because expression of type 'string' can't be used to index
提问by DLee
Trying out TypeScript for a React project and I'm stuck on this error:
为 React 项目尝试 TypeScript 时遇到了这个错误:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ train_1: boolean; train_2: boolean; train_3: boolean; train_4: boolean; }'.
No index signature with a parameter of type 'string' was found on type '{ train_1: boolean; train_2: boolean; train_3: boolean; train_4: boolean; }'
Which appears when I try to filter the array in my component
当我尝试过滤组件中的数组时出现
.filter(({ name }) => plotOptions[name]);
So far I looked at the article "Indexing objects in TypeScript" (https://dev.to/kingdaro/indexing-objects-in-typescript-1cgi) since it had a similar error, but I tried to add the index signature to type plotTypes
and I still get the same error.
到目前为止,我查看了文章“在 TypeScript 中索引对象”(https://dev.to/kingdaro/indexing-objects-in-typescript-1cgi),因为它有类似的错误,但我尝试将索引签名添加到键入plotTypes
,我仍然遇到相同的错误。
My component code:
我的组件代码:
import React, { Component } from "react";
import createPlotlyComponent from "react-plotly.js/factory";
import Plotly from "plotly.js-basic-dist";
const Plot = createPlotlyComponent(Plotly);
interface IProps {
data: any;
}
interface IState {
[key: string]: plotTypes;
plotOptions: plotTypes;
}
type plotTypes = {
[key: string]: boolean;
train_1: boolean;
train_2: boolean;
train_3: boolean;
train_4: boolean;
};
interface trainInfo {
name: string;
x: Array<number>;
y: Array<number>;
type: string;
mode: string;
}
class FiltrationPlots extends Component<IProps, IState> {
readonly state = {
plotOptions: {
train_1: true,
train_2: true,
train_3: true,
train_4: true
}
};
render() {
const { data } = this.props;
const { plotOptions } = this.state;
if (data.filtrationData) {
const plotData: Array<trainInfo> = [
{
name: "train_1",
x: data.filtrationData.map((i: any) => i["1-CumVol"]),
y: data.filtrationData.map((i: any) => i["1-PressureA"]),
type: "scatter",
mode: "lines"
},
{
name: "train_2",
x: data.filtrationData.map((i: any) => i["2-CumVol"]),
y: data.filtrationData.map((i: any) => i["2-PressureA"]),
type: "scatter",
mode: "lines"
},
{
name: "train_3",
x: data.filtrationData.map((i: any) => i["3-CumVol"]),
y: data.filtrationData.map((i: any) => i["3-PressureA"]),
type: "scatter",
mode: "lines"
},
{
name: "train_4",
x: data.filtrationData.map((i: any) => i["4-CumVol"]),
y: data.filtrationData.map((i: any) => i["4-PressureA"]),
type: "scatter",
mode: "lines"
}
].filter(({ name }) => plotOptions[name]);
return (
<Plot
data={plotData}
layout={{ width: 1000, height: 1000, title: "A Fancy Plot" }}
/>
);
} else {
return <h1>No Data Loaded</h1>;
}
}
}
export default FiltrationPlots;
回答by Fyodor
This happens because you try to access plotOptions
property using string name
. TypeScript understands that name
may have any value, not only property name from plotOptions
. So TypeScript requires to add index signature to plotOptions
, so it knows that you can use any property name in plotOptions
. But I suggest to change type of name
, so it can only be one of plotOptions
properties.
发生这种情况是因为您尝试plotOptions
使用 string访问属性name
。TypeScript 理解它name
可能具有任何值,而不仅仅是来自plotOptions
. 所以TypeScript 需要给. 添加索引签名plotOptions
,所以它知道你可以在plotOptions
. 但我建议更改 的类型name
,因此它只能是plotOptions
属性之一。
interface trainInfo {
name: keyof typeof plotOptions;
x: Array<number>;
y: Array<number>;
type: string;
mode: string;
}
Now you'll be able to use only property names that exist in plotOptions
.
现在,您将只能使用存在于plotOptions
.
You also have to slightly change your code.
您还必须稍微更改您的代码。
First assign array to some temp variable, so TS knows array type:
首先将数组分配给某个临时变量,以便 TS 知道数组类型:
const plotDataTemp: Array<trainInfo> = [
{
name: "train_1",
x: data.filtrationData.map((i: any) => i["1-CumVol"]),
y: data.filtrationData.map((i: any) => i["1-PressureA"]),
type: "scatter",
mode: "lines"
},
// ...
}
Then filter:
然后过滤:
const plotData = plotDataTemp.filter(({ name }) => plotOptions[name]);
If you're getting data from API and have no way to type check props at compile time the only way is to add index signature to your plotOptions
:
如果您从 API 获取数据并且无法在编译时键入检查道具,唯一的方法是将索引签名添加到您的plotOptions
:
type tplotOptions = {
[key: string]: boolean
}
const plotOptions: tplotOptions = {
train_1: true,
train_2: true,
train_3: true,
train_4: true
}
回答by Alex Mckay
// 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'
回答by Zeke
This is what it worked for me. The tsconfig.json
has an option noImplicitAny
that it was set to true
, I just simply set it to false
and now I can access properties in objects using strings.
这就是它对我有用的东西。该tsconfig.json
有一个选项noImplicitAny
,它被设置为true
,我只是单纯地将它设置为false
,现在我可以在使用字符串对象的访问性能。