जब मैं noImplicitAny ध्वज सक्षम के साथ टाइपस्क्रिप्ट संकलित करता हूं, तो मैं त्रुटि "ऑब्जेक्ट के इंडेक्स हस्ताक्षर को स्पष्ट रूप से 'किसी भी प्रकार का" कैसे रोक सकता हूं?


309

मैं हमेशा झंडे के साथ टाइपस्क्रिप्ट संकलित करता हूं --noImplicitAny। यह समझ में आता है क्योंकि मैं चाहता हूं कि मेरे प्रकार की जाँच यथासंभव तंग हो।

मेरी समस्या यह है कि निम्नलिखित कोड के साथ मुझे त्रुटि मिलती है Index signature of object type implicitly has an 'any' type:

interface ISomeObject {
    firstKey:   string;
    secondKey:  string;
    thirdKey:   string;
}

let someObject: ISomeObject = {
    firstKey:   'firstValue',
    secondKey:  'secondValue',
    thirdKey:   'thirdValue'
};

let key: string = 'secondKey';

let secondValue: string = someObject[key];

ध्यान रखना महत्वपूर्ण है कि यह विचार है कि कुंजी चर अनुप्रयोग में कहीं और से आता है और वस्तु में कोई भी कुंजी हो सकती है।

मैंने स्पष्ट रूप से टाइप करके कास्टिंग करने की कोशिश की है:

let secondValue: string = <string>someObject[key];

या मेरा परिदृश्य अभी संभव नहीं है --noImplicitAny?

जवाबों:


337

एक सूचकांक हस्ताक्षर जोड़ने से टाइपस्क्रिप्ट को पता चल जाएगा कि प्रकार क्या होना चाहिए।

आपके मामले में ऐसा ही होगा [key: string]: string;

interface ISomeObject {
    firstKey:      string;
    secondKey:     string;
    thirdKey:      string;
    [key: string]: string;
}

हालाँकि, यह सभी प्रकार की संपत्ति को सूचकांक हस्ताक्षर से मेल खाने के लिए भी लागू करता है। चूंकि सभी गुण एक हैं stringयह काम करता है।

जबकि सूचकांक हस्ताक्षर सरणी और 'डिक्शनरी' पैटर्न का वर्णन करने का एक शक्तिशाली तरीका है, वे यह भी लागू करते हैं कि सभी गुण उनके रिटर्न प्रकार से मेल खाते हैं।

संपादित करें:

यदि प्रकार मेल नहीं खाते हैं, तो एक संघ प्रकार का उपयोग किया जा सकता है [key: string]: string|IOtherObject;

संघ प्रकारों के साथ, यदि आप टाइपस्क्रिप्ट को परिभाषित करने के बजाय टाइप करने देते हैं तो यह बेहतर है।

// Type of `secondValue` is `string|IOtherObject`
let secondValue = someObject[key];
// Type of `foo` is `string`
let foo = secondValue + '';

हालाँकि अगर आप इंडेक्स हस्ताक्षरों में बहुत सारे प्रकार के हैं तो थोड़ा गड़बड़ हो सकता है। इसका विकल्प anyहस्ताक्षर में उपयोग करना है। [key: string]: any;फिर आपको उन प्रकारों को डालना होगा जैसे आपने ऊपर किया था।


और अगर आपका इंटरफ़ेस इंटरफ़ेस की तरह दिखता है ISomeObject {firstKey: string; secondKey: IOtherObject; } यह संभव नहीं है मुझे लगता है?
— जैस्पर शुल्त्

धन्यवाद! किसी भी प्रकार के संयोजन के साथ एक प्रकार प्रति केस के संयोजन में जाने के लिए एक बेचा तरीका लगता है।
— जैस्पर शुल्टे ऑक्ट

नमस्ते, कैसे "anyObject [कुंजी: वस्तु] ['नाम'] को संभालने के लिए?
— कोड_कैश

या ऐसा कुछ कहें जैसे कि _obj = {}; let _dbKey = _props [कुंजी] ['नाम']; _obj [_dbKey] = यह [कुंजी]; यहाँ _प्रॉप्स ऑब्जेक्ट और ऑब्जेक्ट है [कुंजी] भी एक ऑब्जेक्ट लौटाएगा जिसके पास नाम संपत्ति होगी।
— कोड_कैश

180

त्रुटि से बचने का दूसरा तरीका यह है कि कलाकारों का उपयोग इस तरह किया जाए:

let secondValue: string = (<any>someObject)[key]; (कोष्ठक नोट करें)

केवल समस्या यह है कि यह अब टाइप-सुरक्षित नहीं है, जैसा कि आप के लिए कास्टिंग कर रहे हैं any । लेकिन आप हमेशा सही प्रकार से वापस कास्ट कर सकते हैं।

ps: मैं टाइपस्क्रिप्ट 1.7 का उपयोग कर रहा हूं, पिछले संस्करणों के बारे में निश्चित नहीं।


20
Tslint की चेतावनियों से बचने के लिए, आप भी इस्तेमाल कर सकते हैं:let secondValue: string = (someObject as any)[key];
— briosheje

96

टाइपस्क्रिप्ट 2.1 ने इस मुद्दे को संभालने का सुरुचिपूर्ण तरीका पेश किया।

const key: (keyof ISomeObject) = 'secondKey';
const secondValue: string = someObject[key];

हम keyofकीवर्ड द्वारा संकलन चरण के दौरान सभी ऑब्जेक्ट प्रॉपर्टी नामों तक पहुँच सकते हैं (देखें चैंज देखें ) के ।

आपको केवल stringचर प्रकार को बदलने की आवश्यकता है keyof ISomeObject। अब कंपाइलर जानता है कि keyवेरिएबल से केवल प्रॉपर्टी के नाम रखने की अनुमति हैISomeObject ।

पूर्ण उदाहरण:

interface ISomeObject {
    firstKey:   string;
    secondKey:  string;
    thirdKey:   number;
}

const someObject: ISomeObject = {
    firstKey:   'firstValue',
    secondKey:  'secondValue',
    thirdKey:   3
};

const key: (keyof ISomeObject) = 'secondKey';
const secondValue: string = someObject[key];

// You can mix types in interface, keyof will know which types you refer to.
const keyNumber: (keyof ISomeObject) = 'thirdKey';
const numberValue: number = someObject[keyNumber];

Typecriptlang.org पर लाइव कोड (सेट noImplicitAnyविकल्प)

अधिक keyofउपयोग के साथ आगे पढ़ना ।


6
लेकिन यह होगा काम नहीं करता है, तो हम घोषणा करते हैं keyके रूप में const key = (keyof ISomeObject)= 'दूसरा' + 'कुंजी'
— निराश

55

निम्नलिखित tsconfig सेटिंग आपको इन त्रुटियों को अनदेखा करने की अनुमति देगा - इसे सही पर सेट करें।

suppressImplicitAnyIndexErrors

अनुक्रमणिका हस्ताक्षर की कमी वस्तुओं को अनुक्रमित करने के लिए noImplicitAny त्रुटियों को दबाएं।


14
ऐसा कुछ है जो आपको नहीं करना चाहिए - शायद आपकी टीम में किसी ने कोड को अधिक बुलेट-प्रूफ बनाने के लिए स्पष्ट रूप से इस संकलक विकल्प को सेट किया है!
— atsu85

12
मैं इससे असहमत हूं कि यह विकल्प किस लिए बनाया गया था: कोष्ठक संकेतन के साथ अनुमति दें --noImplicitAny। मैच पूरी तरह से op के सवाल।
— घेटोले

4
मैं @Ghetolay से सहमत हूं। यह भी एकमात्र विकल्प है यदि इंटरफ़ेस को संशोधित करना संभव नहीं है। उदाहरण के लिए, जैसे आंतरिक इंटरफेस XMLHttpRequest।
— मार्को रॉय

1
मैं @Ghetolay से भी सहमत हूं। मुझे उत्सुकता है कि यह पेड्रो विला वर्डे के उत्तर से गुणात्मक रूप से कैसे अलग है (इस तथ्य के अलावा कि कोड कम बदसूरत है)। हम सभी जानते हैं कि यदि संभव हो तो एक स्ट्रिंग का उपयोग करके किसी ऑब्जेक्ट प्रॉपर्टी तक पहुंचने से बचा जाना चाहिए, लेकिन हम कभी-कभी जोखिम को समझते हुए उस स्वतंत्रता का आनंद लेते हैं।
— स्टीफन पॉल

यह केवल व्यापार है। आपको जो पसंद है उसे चुनें: कम त्रुटि सतह क्षेत्र और सख्त सूचकांक पहुंच, या त्रुटियों के लिए अधिक सतह क्षेत्र है और आसानी से अज्ञात सूचक तक पहुंच सकते हैं। TS2.1 keyofऑपरेटर सब कुछ सख्त रखने में मदद कर सकता है, पियोट्र का जवाब देखें!
— त्रिकुट्र

24

उपरोक्त वर्णित 'कीफ' समाधान काम करता है। लेकिन अगर चर का उपयोग केवल एक बार किया जाता है जैसे किसी वस्तु आदि के माध्यम से लूपिंग, तो आप इसे टाइपकास्ट भी कर सकते हैं।

for (const key in someObject) {
    sampleObject[key] = someObject[key as keyof ISomeObject];
}

धन्यवाद। यह किसी अन्य ऑब्जेक्ट की कुंजियों को पुनरावृत्त करते समय मनमाने ढंग से कुंजी एक्सेस के लिए काम करता है।
— बुकाबै

18

उपयोग keyof typeof

const cat = {
    name: 'tuntun'
}

const key: string = 'name' 

cat[key as keyof typeof cat]

7

@Pootr Lewandowski के जवाब के समान, लेकिन एक के भीतर forEach:

const config: MyConfig = { ... };

Object.keys(config)
  .forEach((key: keyof MyConfig) => {
    if (config[key]) {
      // ...
    }
  });

आपको यह काम करने के लिए कैसे मिला? मैं, एक ही बात (टीएस 3.8.3) कोशिश कर रहा हूँ, हालांकि यह कहते हुए एक त्रुटि फेंकता है: Argument of type '(field: "id" | "url" | "name") => void' is not assignable to parameter of type '(value: string, index: number, array: string[]) => void'। मेरा कोड ऐसा दिखता है Object.keys(components).forEach((comp: Component) => {...}, जहां Componentएक प्रकार (जैसे MyConfig) है।
— theGirrafish


6

कोई अनुक्रमणिका नहीं? फिर अपना बना लो!

मैंने विश्व स्तर पर इसे वस्तु हस्ताक्षर को परिभाषित करने का एक आसान तरीका के रूप में परिभाषित किया है। यदि आवश्यक Tहो anyतो हो सकता है:

type Indexer<T> = { [ key: string ]: T };

मैं सिर्फ indexerएक वर्ग के सदस्य के रूप में जोड़ता हूं ।

indexer = this as unknown as Indexer<Fruit>;

इसलिए मैं इसे समाप्त करता हूं:

constructor(private breakpointResponsiveService: FeatureBoxBreakpointResponsiveService) {

}

apple: Fruit<string>;
pear: Fruit<string>;

// just a reference to 'this' at runtime
indexer = this as unknown as Indexer<Fruit>;

something() {

    this.indexer['apple'] = ...    // typed as Fruit

ऐसा करने का लाभ यह है कि आपको उचित प्रकार वापस मिल जाता है - कई समाधान जो उपयोग करते हैं <any>, वे आपके लिए टाइपिंग खो देंगे। याद रखें यह कोई रनटाइम सत्यापन नहीं करता है। यदि आपको कुछ मौजूद है या नहीं, यह सुनिश्चित करने के लिए आपको अभी भी जाँच करनी होगी कि क्या यह मौजूद है।

यदि आप अत्यधिक सतर्क रहना चाहते हैं, और आप उन strictसभी स्थानों को प्रकट करने के लिए ऐसा कर रहे हैं, तो आपको एक स्पष्ट अपरिभाषित चेक करने की आवश्यकता हो सकती है:

type OptionalIndexed<T> = { [ key: string ]: T | undefined };

मुझे आमतौर पर यह आवश्यक नहीं लगता है क्योंकि अगर मेरे पास कहीं से एक स्ट्रिंग संपत्ति के रूप में है तो मुझे आमतौर पर पता है कि यह वैध है।

मुझे यह विधि विशेष रूप से उपयोगी लगी है यदि मेरे पास बहुत सारे कोड हैं जिन्हें अनुक्रमणिका तक पहुंचने की आवश्यकता है, और टाइपिंग को केवल एक स्थान पर बदला जा सकता है।

नोट: मैं strictमोड का उपयोग कर रहा हूं , और unknownनिश्चित रूप से आवश्यक है।

संकलित कोड बस होगा indexer = this, इसलिए यह बहुत समान है जब टाइपस्क्रिप्ट _this = thisआपके लिए बनाता है।


1
कुछ मामलों में आप Record<T>इसके बजाय प्रकार का उपयोग करने में सक्षम हो सकते हैं - मैं अभी इस के बारीक विवरण पर शोध करने में सक्षम नहीं हूं, लेकिन कुछ सीमित मामलों के लिए यह बेहतर काम कर सकता है।
— शमौन_ वीवर

5

'अनुक्रमणिका' इंटरफ़ेस को परिभाषित करने के लिए एक इंटरफ़ेस बनाएँ

फिर उस सूचकांक के साथ अपनी वस्तु बनाएं।

नोट: इसमें अभी भी वही मुद्दे होंगे जो अन्य उत्तर ने प्रत्येक आइटम के प्रकार को लागू करने के संबंध में वर्णित किए हैं - लेकिन यह अक्सर वही है जो आप चाहते हैं।

आप जेनेरिक प्रकार का पैरामीटर बना सकते हैं जो आपको चाहिए: ObjectIndexer< Dog | Cat>

// this should be global somewhere, or you may already be 
// using a library that provides such a type
export interface ObjectIndexer<T> {
  [id: string]: T;
}

interface ISomeObject extends ObjectIndexer<string>
{
    firstKey:   string;
    secondKey:  string;
    thirdKey:   string;
}

let someObject: ISomeObject = {
    firstKey:   'firstValue',
    secondKey:  'secondValue',
    thirdKey:   'thirdValue'
};

let key: string = 'secondKey';

let secondValue: string = someObject[key];

टाइपस्क्रिप्ट खेल का मैदान


आप सामान्य प्रकार को परिभाषित करते समय एक सामान्य बाधा में भी इसका उपयोग कर सकते हैं :

export class SmartFormGroup<T extends IndexableObject<any>> extends FormGroup

तब Tवर्ग के अंदर अनुक्रमित किया जा सकता है :-)


मैं वहाँ एक मानक 'में निर्मित' के लिए इंटरफ़ेस है नहीं लगता है Dictionaryकि प्रतिनिधित्व करता { [key: string]: T }है, लेकिन मेरी दूर करने के लिए अगर वहाँ कभी कृपया संपादित इस सवाल है ObjectIndexer।
— सिमोन_विवर

3

डिक्लेयर प्रकार जो इसकी कुंजी स्ट्रिंग है और मान किसी भी हो सकता है तब इस प्रकार के साथ ऑब्जेक्ट घोषित करें और लिंट दिखाई नहीं देगा

type MyType = {[key: string]: any};

तो आपका कोड होगा

type ISomeType = {[key: string]: any};

    let someObject: ISomeType = {
        firstKey:   'firstValue',
        secondKey:  'secondValue',
        thirdKey:   'thirdValue'
    };

    let key: string = 'secondKey';

    let secondValue: string = someObject[key];

1

आज बेहतर समाधान के लिए प्रकारों की घोषणा करना है। पसंद

enum SomeObjectKeys {
    firstKey = 'firstKey',
    secondKey = 'secondKey',
    thirdKey = 'thirdKey',
}

let someObject: Record<SomeObjectKeys, string> = {
    firstKey:   'firstValue',
    secondKey:  'secondValue',
    thirdKey:   'thirdValue',
};

let key: SomeObjectKeys = 'secondKey';

let secondValue: string = someObject[key];

1

3 चरणों में टाइपस्क्रिप्ट 3.1 का उपयोग करके मुझे जो सबसे सरल समाधान मिल सकता है वह है:

1) इंटरफ़ेस बनाओ

interface IOriginal {
    original: { [key: string]: any }
}

2) टाइप की हुई कॉपी बनाएं

let copy: IOriginal = (original as any)[key];

3) कहीं भी उपयोग करें (JSX शामिल)

<input customProp={copy} />
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.