Element implicitly has an 'any' type because expression of type 'string' can't be used to index type

avatar

Borislav Hadzhiev

Tue Mar 08 20223 min read

banner

Photo by Warren Wong

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type #

The error "Element implicitly has an 'any' type because expression of type 'string' can't be used to index type" occurs when we use a string to index an object with specific keys. To solve the error, type the string as one of the object's keys.

Here is an example of how the error occurs.

index.ts
const str = 'name' as string; const obj = { name: 'James Doe', country: 'Chile', }; // ⛔️ Error: Element implicitly has an 'any' type // because expression of type 'string' can't be used // to index type '{ name: string; }'. // No index signature with a parameter of type 'string' // was found on type '{ name: string; }'.ts(7053) obj[str];

The str variable has a type of string and this could be any string.

We get the error when we try to access an object that has a name and country properties.

TypeScript is telling us that the type string is too broad and not all strings are keys in the object, so we have to make sure the specific string is one of the object's keys.

The first way to solve the error is to use a type assertion.

index.ts
const str = 'name' as string; const obj = { name: 'James Doe', country: 'Chile', }; // 👇️ "James Doe" console.log(obj[str as keyof typeof obj]); // 👇️ type T = "name" | "country" type T = keyof typeof obj;

We used a type assertion to indicate to TypeScript that the str variable is not of type string, but rather it is a union type containing only the keys of the object.

Now TypeScript lets us access the specific property without throwing the error.

We used keyof typeof to get a union type of the object's keys.

If you are working with a type directly, you would just use keyof MyType to get a union of the object's keys.

index.ts
const str = 'name' as string; interface Person { name: string; country: string; } const obj: Person = { name: 'James Doe', country: 'Chile', }; console.log(obj[str as keyof Person]); // 👉️ "James Doe" // 👇️ type T = "name" | "country" type T = keyof Person;

Notice that we used keyof Person and not keyof typeof Person, because Person is a type, and not an object.

An even better way to solve this issue is to type the str variable as keyof Person to indicate to TypeScript that the string will only ever be one of the object's keys.

index.ts
interface Person { name: string; country: string; } // 👇️ this will only ever be one of object's keys const str: keyof Person = 'name'; const obj: Person = { name: 'James Doe', country: 'Chile', }; console.log(obj[str]); // 👉️ "James Doe"

Now we don't have to use any type assertions, which is much better.

Type assertions are used when we have information about the type of a value that TypeScript can't know about.

When using them, we effectively tell TypeScript that value X will be of type Y and not to worry about it. This could cause runtime errors if we are wrong.

Here is another example of how you could type a value to only be one of the object's keys.

index.ts
interface Person { name: string; country: string; } const obj1: Person = { name: 'James Doe', country: 'Chile', }; interface AccessPerson { keyName: keyof Person; // 👈️ only one of Person's keys } const obj2: AccessPerson = { keyName: 'country', }; console.log(obj1[obj2.keyName]); // 👉️ "Chile"

We are using the obj2.keyName property to access a property in obj1.

To be able to do this, we had to type the keyName property in obj2 to be of type keyof Person.

The keyName property in obj2 can only ever have a value of name or country, so TypeScript allows us to safely access the specific properties in obj1.

This is necessary, because not all string values in the world are keys in the specific object. For TypeScript to let us access the object's properties, we have to convince it that the string is one of the object's keys.

This is the most type safe solution to the error, because if we ever try to change the value of obj2.keyName to an incompatible type, we'd get an error.

index.ts
interface Person { name: string; country: string; } interface AccessPerson { keyName: keyof Person; } const obj2: AccessPerson = { keyName: 'country', }; // ⛔️ Error: Type '"hello"' is not // assignable to type 'keyof Person'.ts(2322) obj2.keyName = 'hello';

Trying to set obj2.keyName to any other value than name or country causes an error.

Use the search field on my Home Page to filter through my more than 1,000 articles.