Zjaaspoer Zjaaspoer - 4 months ago 374
TypeScript Question

How do I prevent the error "Index signature of object type implicitly has an 'any' type" when compiling typescript with noImpicitAny flag enabled?

I always compile Typescript with the flag --noImplicitAny. This makes sense as I want my type checking to be as tight as possible.

My problem is that with the following code I get the error

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


Important to note is that the idea is that the key variable comes from somewhere else in the application and can be any of the keys in the object.

I've tried explicitly casting the type by:

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


Or is my scenario just not possible with
--noImplicitAny
?

Answer

Adding an index signature will let TypeScript know what the type should be.

In your case that would be [key: string]: string;

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

However, this also enforces all of the property types to match the index signature. Since all of the properties are a string it works.

While index signatures are a powerful way to describe the array and 'dictionary' pattern, they also enforce that all properties match their return type.

Edit:

If the types don't match, a union type can be used [key: string]: string|IOtherObject;

With union types, it's better if you let TypeScript infer the type instead of defining it.

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

Although that can get a little messy if you have a lot of different types in the index signatures. The alternative to that is to use any in the signature. [key: string]: any; Then you would need to cast the types like you did above.