为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; }'
当我尝试过滤组件中的数组时出现哪个
.filter(({ name }) => plotOptions[name]);
到目前为止,我看了这篇文章“在TypeScript中为对象建立索引”(https://dev.to/kingdaro/indexing-objects-in-typescript-1cgi),因为它有类似的错误,但是我尝试将索引签名添加到plotTypes类型,但仍然遇到相同的错误。
下面是我的组件代码:
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;
我对此表示感谢。我真的是Typescript的新手,所以欢迎任何指导或建议
答案 0 :(得分:32)
// 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];
错误-错误的原因是object
类型默认情况下只是一个空对象。因此,不可能使用string
类型来索引{}
。
更好-错误消失的原因是因为现在我们告诉编译器obj
参数将是字符串/值(string/any
)对的集合。但是,我们使用的是any
类型,所以我们可以做得更好。
最佳-T
扩展空对象。 U
扩展了T
的键。因此U
将始终存在于T
上,因此可以用作查找值。
以下是完整示例:
我已更改了泛型的顺序(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'
const getKeyValue = <T, K extends keyof T>(obj: T, key: K): T[K] => obj[key];
答案 1 :(得分:8)
我使用这个:
interface IObjectKeys {
[key: string]: string | number;
}
interface IDevice extends IObjectKeys {
id: number;
room_id: number;
name: string;
type: string;
description: string;
}
答案 2 :(得分:6)
我已经对问题进行了模拟。看起来问题是我们应该如何 在 Typescript 中使用括号表示法动态访问对象属性
interface IUserProps {
name: string;
age: number;
}
export default class User {
constructor(private data: IUserProps) {}
get(propName: string): string | number {
return this.data[propName as keyof IUserProps];
}
}
我发现了一个可能有助于更好地理解这一点的博客。
答案 3 :(得分:5)
使用Object.keys
时,以下工作正常:
Object.keys(this)
.forEach(key => {
console.log(this[key as keyof MyClass]);
});
答案 4 :(得分:4)
当我们执行类似obj [key]的操作时,Typescript不能确定该键是否存在于该对象中。我做了什么:
Object.entries(data).forEach(item => {
formData.append(item[0], item[1]);
});
答案 5 :(得分:1)
发生这种情况是因为您尝试使用字符串plotOptions
访问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;
}
现在,您将只能使用plotOptions
中存在的属性名称。
您还必须稍微更改代码
首先将数组分配给一些临时变量,以便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"
},
// ...
}
比过滤器
const plotData = plotDataTemp.filter(({ name }) => plotOptions[name]);
如果您要从API获取数据,并且无法在编译时进行类型检查道具,则唯一的方法是将索引签名添加到您的plotOptions
type tplotOptions = {
[key: string]: boolean
}
const plotOptions: tplotOptions = {
train_1: true,
train_2: true,
train_3: true,
train_4: true
}
答案 6 :(得分:0)
没有typescript
错误
const formData = new FormData();
Object.keys(newCategory).map((k,i)=>{
var d =Object.values(newCategory)[i];
formData.append(k,d)
})
答案 7 :(得分:0)
感谢Alex Mckay,我决心动态设置道具:
for(let prop in filter)
(state.filter as Record<string, any>)[prop] = filter[prop];
答案 8 :(得分:0)
我对Alex McKay的功能/用法做了一些小改动,我认为这样可以更轻松地了解其工作原理,并遵循no-use-before-define规则。
首先,定义要使用的函数:
const getKeyValue = function<T extends object, U extends keyof T> (obj: T, key: U) { return obj[key] }
按照我的编写方式,该函数的泛型首先列出对象,然后列出对象的属性(这些可以以任何顺序发生,但是如果在{{1之前指定U extends key of T
}}打破了T extends object
规则,并且首先拥有对象及其第二个属性也很有意义。最后,我使用了更通用的函数语法代替了箭头运算符({{1} }。
无论如何,只要进行了这些修改,就可以像这样使用它:
no-use-before-define
再次,我发现它更具可读性。
答案 9 :(得分:-11)
这对我有用。 tsconfig.json
的选项noImplicitAny
设置为true
,我只是将其设置为false
,现在我可以使用字符串访问对象的属性。