NoImplicitAny bayrağı etkinken daktiloyu derlerken “Nesne türünün dizin imzasının dolaylı olarak 'herhangi bir' türü var” hatasını nasıl önleyebilirim?


309

Her zaman - --IImplicitAny bayrağı ile Typescript derlemek. Tip kontrolümün olabildiğince sıkı olmasını istediğim için bu mantıklı.

Benim sorunum şu kod ile hatayı alıyorum 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];

Dikkat edilmesi gereken önemli nokta, anahtar değişkenin uygulamada başka bir yerden gelmesi ve nesnedeki anahtarlardan herhangi biri olabilmesidir.

Açıkça tarafından tür döküm denedim:

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

Yoksa benim senaryom mümkün değil --noImplicitAnymi?

Yanıtlar:


337

Bir dizin imzası eklemek TypeScript'e türün ne olması gerektiğini bildirir.

Senin durumunda [key: string]: string;

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

Ancak bu, tüm özellik türlerinin dizin imzasıyla eşleşmesini sağlar. Tüm özellikler bir stringolduğu için çalışır.

Dizin imzaları diziyi ve 'sözlük' kalıbını tanımlamanın güçlü bir yolu olsa da, tüm özelliklerin dönüş türleriyle eşleşmesini zorunlu kılar.

Düzenle:

Türler eşleşmezse, bir birleşim türü kullanılabilir [key: string]: string|IOtherObject;

Birleştirme türlerinde, TypeScript'in türü tanımlamak yerine çıkarım yapmasına izin vermek daha iyidir.

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

Eğer dizin imzaları çok farklı türleri varsa bu biraz dağınık olabilir. Bunun alternatifi imzada kullanmaktır any. [key: string]: any;O zaman yukarıda yaptığınız gibi türleri dökmeniz gerekir.


Arayüzünüz ISomeObject {firstKey: string arayüzüne benziyorsa; secondKey: IOtherObject; } bu mümkün değil sanırım?
Jasper Schulte

Teşekkürler! Herhangi bir türün, vaka başına bir tür dökümü ile birlikte kombinasyonu, satılan bir yol gibi görünüyor.
Jasper Schulte

Merhaba, "anyObject [key: Object] ['name']" nasıl işlenir?
Code_Crash

veya _obj = {} gibi bir şey söyleyin; let _dbKey = _props [anahtar] ['ad']; _obj [_dbKey] = bu [anahtar]; burada _props nesne ve nesne [anahtar] ayrıca name özelliğine sahip bir nesne döndürür.
Code_Crash

180

Hatayı önlemenin bir başka yolu da oyuncu kadrosunu şu şekilde kullanmaktır:

let secondValue: string = (<any>someObject)[key]; (Parantezlere dikkat edin)

Tek sorun, artık yayınladığınız gibi bu tür bir güvenli değil any. Ancak her zaman doğru türe geri dönebilirsiniz.

ps: typescript 1.7 kullanıyorum, önceki sürümlerden emin değilim.


20
Tslint uyarılarını önlemek için şunları da kullanabilirsiniz:let secondValue: string = (someObject as any)[key];
briosheje

96

TypeScript 2.1 , bu sorunu çözmek için zarif bir yol sundu.

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

Derleme aşamasında tüm nesne özellik adlarına keyofanahtar sözcükle erişebiliriz (bkz. Changelog ).

stringDeğişken türünü yalnızca ile değiştirmeniz gerekir keyof ISomeObject. Derleyici key, değişkenin yalnızca özellik adlarını içermesine izin verildiğini biliyor ISomeObject.

Tam örnek:

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

Typescriptlang.org'da canlı kod (ayar noImplicitAnyseçeneği)

Daha fazla keyofkullanımla daha fazla okuma .


6
Ancak = 'ikinci' + 'Anahtar' keyolarak ilan edersek işe yaramazconst key = (keyof ISomeObject)
Hayal kırıklığı

55

Aşağıdaki tsconfig ayarı , bu hataları yok saymanıza olanak tanır - true olarak ayarlayın.

suppressImplicitAnyIndexErrors

Dizin imzaları olmayan nesneleri indekslemek için noImplicitAny hatalarını bastırın.


14
Bu, yapmamanız gereken bir şeydir - muhtemelen ekibinizdeki biri kodu daha kurşun geçirmez hale getirmek için bu derleyici seçeneğini açıkça belirlemiştir!
atsu85

12
Bu seçeneğin tam olarak ne için yapıldığına katılmıyorum: Parantez gösterimine izin ver --noImplicitAny. Mükemmel op sorusunu eşleştirin.
Ghetolay

4
@Ghetolay ile hemfikirim. Bu, arayüzde değişiklik yapılamıyorsa tek seçenektir. Örneğin, gibi iç arabirimlerle XMLHttpRequest.
Marco Roy

1
Ayrıca @Ghetolay ile hemfikirim. Bunun Pedro Villa Verde'nin cevabından (kodun daha az çirkin olması dışında) nasıl niteliksel olarak farklı olduğunu merak ediyorum. Mümkünse dize kullanarak bir nesne özelliğine erişmekten kaçınılması gerektiğini hepimiz biliyoruz, ancak bazen riskleri anlarken bu özgürlüğün tadını çıkarıyoruz.
Stephen Paul

Bu sadece ödünleşmeler. İstediğinizi seçin: daha az hata yüzey alanı ve katı dizin erişimi veya hatalar için daha fazla yüzey alanına sahip olun ve bilinmeyen indekslere kolayca erişin. TS2.1 keyofoperatörü her şeyi sıkı tutmaya yardımcı olabilir, Piotr'un cevabına bakın!
trusktr

24

Yukarıda belirtilen 'anahtar' çözüm işe yarar. Ancak, değişken yalnızca bir kez kullanılırsa, örneğin bir nesne vb. Üzerinden döngü yaparak, bunu da tahmin edebilirsiniz.

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

Teşekkürler. Bu, başka bir nesnenin anahtarlarını yinelerken rastgele anahtar erişimi için çalışır.
bucabay

19

kullanım keyof typeof

const cat = {
    name: 'tuntun'
}

const key: string = 'name' 

cat[key as keyof typeof cat]

7

@Piotr Lewandowski'nin cevabına benzer, ancak aşağıdakiler dahilinde forEach:

const config: MyConfig = { ... };

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

Bunu nasıl elde ettiniz? O belirten bir hata atar rağmen, aynı şeyi (3.8.3 ts) çalışıyorum: Argument of type '(field: "id" | "url" | "name") => void' is not assignable to parameter of type '(value: string, index: number, array: string[]) => void'. Kodum böyle görünüyor , bir tür Object.keys(components).forEach((comp: Component) => {...}nerede Component(gibi MyConfig).
theGirrafish

6

Nesneyi böyle ilan edin.

export interface Thread {
    id:number;
    messageIds: number[];
    participants: {
        [key:number]: number
    };
}

6

Dizin oluşturucu yok mu? Sonra kendiniz yapın!

Küresel olarak bunu bir nesne imzasını tanımlamanın kolay bir yolu olarak tanımladım. gerekirse Tolabilir any:

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

Sadece indexersınıf üyesi olarak ekliyorum .

indexer = this as unknown as Indexer<Fruit>;

Bu yüzden bununla bitirdim:

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

Bunu yapmanın yararı, uygun türü geri almanızdır - kullanılan birçok çözüm <any>yazmayı sizin için kaybeder. Bunun herhangi bir çalışma zamanı doğrulaması yapmadığını unutmayın. Hala olduğundan emin değilseniz, bir şey olup olmadığını kontrol etmeniz gerekir.

Aşırı temkinli olmak istiyorsanız ve kullanıyorsanız strict, açık bir tanımsız denetim yapmanız gerekebilecek tüm yerleri ortaya çıkarmak için bunu yapabilirsiniz:

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

Ben genellikle bir yerde dize özelliği olarak varsa ben genellikle geçerli olduğunu biliyorum çünkü bu gerekli bulamıyorum.

Bu yöntemi özellikle dizinleyici erişmek için gereken bir sürü kod varsa ve yazarak sadece bir yerde değiştirilebilir yararlı buldum.

Not: strictModu kullanıyorum ve unknownkesinlikle gerekli.

Derlenmiş kod sadece olacak indexer = this, bu yüzden patlama yazı tipinin _this = thissizin için oluşturduğu zamana çok benzer .


1
Bazı durumlarda Record<T>bunun yerine türü kullanabilirsiniz - şu anda bunun ince ayrıntılarını araştıramadım, ancak bazı sınırlı durumlarda daha iyi çalışabilir.
Simon_Weaver

5

'Dizin oluşturucu' arayüzünü tanımlamak için bir arayüz oluşturun

Ardından nesnenizi bu dizinle oluşturun.

Not: Bu, her bir öğenin türünü uygulamakla ilgili diğer cevapların açıkladığı sorunlarla aynı olacaktır - ancak genellikle tam olarak istediğiniz şeydir.

Genel tip parametresini istediğiniz her şeyi yapabilirsiniz: 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];

Yazı Bahçesi


Genel bir tür tanımlarken bunu genel bir kısıtlamayla bile kullanabilirsiniz :

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

Sonra Tsınıf içinde dizine alınabilir :-)


Ben 'yerleşik' için arayüz standart var sanmıyorum Dictionaryo temsil { [key: string]: T }fakat şimdiye lütfen düzenlemek bu soruyu varsa gözlerimi kaldırmak için ObjectIndexer.
Simon_Weaver

3

Anahtarının dize ve değerin herhangi biri olabileceği tür bildir, daha sonra nesneyi bu türle bildir ve tüy bırakma gösterilmez

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

Yani kodunuz

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

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

    let key: string = 'secondKey';

    let secondValue: string = someObject[key];

1

Günümüzde daha iyi bir çözüm türleri beyan etmektir. Sevmek

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 adımda Typescript 3.1 kullanarak bulabildiğim en basit çözüm :

1) arayüz yapmak

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

2) Yazılan bir kopyasını oluşturun

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

3) Her yerde kullanın (JSX dahil)

<input customProp={copy} />
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.