तत्व का स्पष्ट रूप से एक 'कोई' प्रकार होता है क्योंकि प्रकार 'स्ट्रिंग' की अभिव्यक्ति का उपयोग सूचकांक में नहीं किया जा सकता है


86

एक प्रतिक्रिया परियोजना के लिए टाइपस्क्रिप्ट की कोशिश कर रहा हूं और मैं इस त्रुटि पर फंस गया हूं:

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

अब तक मैंने लेख "टाइपस्क्रिप्ट में इंडेक्सिंग ऑब्जेक्ट्स" ( 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;

जवाबों:


84

ऐसा इसलिए होता है क्योंकि आप plotOptionsस्ट्रिंग का उपयोग करके संपत्ति तक पहुंचने का प्रयास करते हैं name। टाइपस्क्रिप्ट समझता है कि nameकिसी भी मूल्य हो सकता है, न कि केवल संपत्ति के नाम से plotOptions। इसलिए टाइपस्क्रिप्ट को इंडेक्स सिग्नेचर को जोड़ने की आवश्यकता है 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
}

29
// 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
मैंने इस फ़ंक्शन के साथ एक छोटा सा एनपीएम पैकेज लिखा है जो टाइपस्क्रिप्ट के लिए नए हैं।
एलेक्स मक्के

पैकेज लगभग 38 बाइट्स है जो एक बार पैक और कीमा बनाया हुआ है।
एलेक्स मैकाय

4

जब हम ऐसा कुछ करते हैं तो obj [key] टाइपस्क्रिप्ट सुनिश्चित नहीं कर सकता है कि क्या वह कुंजी उस ऑब्जेक्ट में मौजूद है। मैंने क्या किया:

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

4

मैं इसका उपयोग करता हूं:

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

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

2

उपयोग करते समय Object.keys, निम्नलिखित कार्य करता है:

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

0

आउट typescriptएरर के साथ

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

0

एलेक्स मकेय के लिए धन्यवाद, मेरे पास गतिशील सेटिंग के लिए एक प्रस्ताव था:

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

0

मैंने एलेक्स मैकके के फ़ंक्शन / उपयोग में कुछ छोटे बदलाव किए हैं जो मुझे लगता है कि यह पालन करना थोड़ा आसान है कि यह क्यों काम करता है और नो- यूज़ -बिफोर रूल का भी पालन करता है ।

सबसे पहले, इस फ़ंक्शन को उपयोग करने के लिए परिभाषित करें:

const getKeyValue = function<T extends object, U extends keyof T> (obj: T, key: U) { return obj[key] }

जिस तरह से मैंने इसे लिखा है, फ़ंक्शन के लिए जेनेरिक पहले ऑब्जेक्ट को सूचीबद्ध करता है, फिर ऑब्जेक्ट दूसरी पर संपत्ति (ये किसी भी क्रम में हो सकती है, लेकिन यदि आप नियम तोड़ने U extends key of Tसे पहले निर्दिष्ट करते हैं , और यह भी सिर्फ समझ में आता है ऑब्जेक्ट को पहले और उसके दूसरे गुण को प्राप्त करने के लिए। अंत में, मैंने तीर ऑपरेटरों ( ) के बजाय अधिक सामान्य फ़ंक्शन सिंटैक्स का उपयोग किया है ।T extends objectno-use-before-define=>

वैसे भी, उन संशोधनों के साथ आप इसे इस तरह उपयोग कर सकते हैं:

interface User {
  name: string;
  age: number;
}

const user: User = {
  name: "John Smith",
  age: 20
};

getKeyValue(user, "name")

जो, फिर से, मुझे थोड़ा अधिक पठनीय लगता है।


-9

यह वही है जो मेरे लिए काम करता है। tsconfig.jsonएक विकल्प होता है noImplicitAnyकि यह करने के लिए स्थापित किया गया था true, मैं सिर्फ बस यह करने के लिए सेट falseऔर अब मैं तार का उपयोग कर वस्तुओं में गुण पहुँच सकते हैं।


6
यह सख्त को हटा देगा, फिर टाइपस्क्रिप्ट का उपयोग करने का कोई मतलब नहीं है अगर हम इन प्रतिबंधों को हटाते रहें।
जोसेफ ब्रिग्स

मैं @JosephBriggs सहमत नहीं हूं। टाइपस्क्रिप्ट तालिका में कई अन्य लाभ लाता है। टाइप चेक उनमें से एक है। यह अच्छा है कि आप अपनी परियोजना की आवश्यकताओं के आधार पर ऑप्ट-इन या आउट कर सकते हैं।
ज़ेके

13
यह समस्या को हल नहीं करता है, यह सिर्फ इसे अनदेखा करता है।
thedayturns 21

1
@Zeke मुझे समझ में आता है :) मैं एक तेजस्वी लेखन में था। मेरा आशय यह है कि यदि हम केवल इसे अनदेखा करने के लिए कहकर मुद्दों को हल करते हैं तो पहली बात में इसका कोई मतलब नहीं है। लेकिन फिर सभी परियोजना पर निर्भर करता है, और प्रति परियोजना निर्णय।
जोसेफ ब्रिग्स

मुझे यह पसंद है ... यहां तक ​​कि मजबूत प्रकार की भाषा जैसे c # में "var" है। बात कर stackoverflow.com/questions/62377614/... ... एक के ऊपर एक सरल संपत्ति का उपयोग करने के लिए कोड जोड़ने से के सभी तरह डाल करने के लिए इंजीनियर बिट।
एरिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.