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

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.


Another way to avoid the error is to use the cast like this:

let secondValue: string = (<any>someObject)[key]; (Note the parenthesis)

The only problem is that this isn't type-safe anymore, as you are casting to any. But you can always cast back to the correct type.

ps: I'm using typescript 1.7, not sure about previous versions.


TypeScript 2.1 introduced elegant way to handle this issue.

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

We can access all object property names during compilation phase by keyof keyword (see changelog).

You only need to replace string variable type with keyof ISomeObject. Now compiler knows key variable is allowed to contain only property names from ISomeObject.

Full example:

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

Live code on typescriptlang.org (set noImplicitAny option)

Further reading with more keyof usages.

Tags:

Typescript