尝试一个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;


当前回答

我用这个:

interface IObjectKeys {
  [key: string]: string | number;
}

interface IDevice extends IObjectKeys {
  id: number;
  room_id: number;
  name: string;
  type: string;
  description: string;
}

注:“[键:字符串]”它是什么?JavaScript中的对象主要是由键值对组成的属性集合。此外,键只能是字符串(即使是数组元素),但值可以是任何数据类型。

如果你在对象中使用可选属性:

interface IDevice extends IObjectKeys {
  id: number;
  room_id?: number;
  name?: string;
  type?: string;
  description?: string;
}

... 你应该在IObjectKeys接口中添加'undefined'值:

interface IObjectKeys {
  [key: string]: string | number | undefined;
}

其他回答

它为我工作的keyof和作为操作符:

const keys: [keyof ITrainInfo] = Object.keys(this.trainInfo) as [
    keyof ITrainInfo,
]
keys.forEach((property) => {
    // console.log(tmpUser[property])
    if (this.trainInfo === undefined) return
    if (this.trainInfo[property] !== undefined) {
        // your code here
        /*const trainsToSet = trains.find((field) => field.name === property)
        if (trainsToSet != undefined)
            trainsToSet.value = this.trainInfo[property]?.toString()
        */
    }
})

发生这种情况是因为您试图使用字符串名称访问plotOptions属性。TypeScript理解name可以有任何值,而不仅仅是plotOptions中的属性name。所以TypeScript需要给plotOptions添加索引签名,这样它就知道你可以在plotOptions中使用任何属性名。但我建议改变名称的类型,所以它只能是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
}

对于将来偶然发现这个的人:

如果你得到TypeScript错误

“…字符串类型的表达式不能用于索引…

然后简单地指定“string类型的表达式”是该对象类型的键。例如,

const someObj:ObjectType = data;
const field = 'username';

// This gives an error
const temp = someObj[field];

// Solution 1: When the type of the object is known
const temp = someObj[field as keyof ObjectType]

// Solution 2: When the type of the object is not known
const temp = someObj[field as keyof typeof someObj]

当使用Object时。按键,以下作品:

Object.keys(this)
    .forEach(key => {
      console.log(this[key as keyof MyClass]);
    });

public getUserName():字符串{

const accessToken = this.getAccessToken();
const claims:any = this.getUserClaims();
console.log('access token ',accessToken);
this.getUserInfo();
return claims['sub'].split('@')[0];

}

//给变量任何类型