[reactjs] ‘문자열’유형의 표현식을 색인화하는 데 사용할 수 없기 때문에 요소에 암시 적으로 ‘모든’유형이 있습니다.

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;



답변

이것은 plotOptionsstring을 사용하여 속성 에 액세스하려고하기 때문에 발생 합니다 name. TypeScript name는의 속성 이름뿐만 아니라 모든 값을 가질 수 있음을 이해합니다 plotOptions. 따라서 TypeScript는에 인덱스 서명을 추가해야하므로 .NET 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에서 데이터를 가져오고 컴파일 타임에 check props를 입력 할 방법이없는 경우 유일한 방법은에 인덱스 서명을 추가하는 것입니다 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하므로 조회 값으로 사용할 수 있습니다.

다음은 전체 예입니다.

제네릭 순서가 중요하지 않다는 점을 강조 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];


답변

우리가 이런 일을 할 때 obj [key] Typescript는 그 키가 그 객체에 존재하는지 확실히 알 수 없습니다. 제가 한:

Object.entries(data).forEach(item => {
    formData.append(item[0], item[1]);
});


답변

나는 이것을 사용한다 :

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

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


답변

를 사용 Object.keys하면 다음이 작동합니다.

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


답변

밖으로 typescript오류

    const formData = new FormData();
    Object.keys(newCategory).map((k,i)=>{
        var d =Object.values(newCategory)[i];
        formData.append(k,d)
    })


답변

Alex Mckay 덕분에 저는 소품을 동적으로 설정하는 결심을했습니다.

  for(let prop in filter)
      (state.filter as Record<string, any>)[prop] = filter[prop];