1. ホーム
  2. reactjs

[解決済み】文字列型の式はインデックスに使えないので、要素は暗黙のうちにany型になる

2022-03-28 11:14:05

質問

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]);

ここまでで、記事 "Indexing objects in TypeScript" を見てみました( https://dev.to/kingdaro/indexing-objects-in-typescript-1cgi ) にも同様のエラーがあったため、indexシグネチャをtypeに追加してみました。 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;


解決方法は?

にアクセスしようとしたために起こります。 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 からデータを取得し、コンパイル時に props をタイプチェックする方法がない場合は、index シグネチャを plotOptions :

type tplotOptions = {
    [key: string]: boolean
}

const plotOptions: tplotOptions = {
    train_1: true,
    train_2: true,
    train_3: true,
    train_4: true
}