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;
これは、文字列plotOptions
を使用してname
プロパティにアクセスしようとしたために発生します。 TypeScriptは、name
からのプロパティ名だけでなく、plotOptions
に任意の値を設定できることを理解しています。 TypeScriptではplotOptions
にインデックスシグネチャを追加する必要があるため、plotOptions
で任意のプロパティ名を使用できることがわかります。ただし、name
のタイプを変更することをお勧めします。そのため、これはplotOptions
プロパティの1つのみにすることができます。
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
}
// 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
に存在するため、ルックアップ値として使用できます。
これは私のために働いたものです。 tsconfig.json
にはオプションnoImplicitAny
があり、true
に設定されていました。これをfalse
に設定するだけで、文字列を使用してオブジェクトのプロパティにアクセスできます。