Beginner’s TypeScript #24

Nhan Nguyen
3 min readJan 27, 2024

Error Message: “Expression Can’t Be Used To Index Type X”

We have an object named productPrices. It has three properties: Apple, Banana, and Orange, each with a price value:

const productPrices = {
Apple: 1.2,
Banana: 0.5,
Orange: 0.8,
}

We also have a function getPrice that takes in a productName as a parameter:

const getPrice = (productName: string) => {
return productPrices[productName]; // red squiggly line under productPrices[productName]
}

The getPrice function is designed to index into the productPrices object using the productName provided.

There is an error under productPrices when trying to index into the object:

// hovering over productPrices[productName] shows:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ Apple: number; Banana: number; Orange: number; }'.

We will figure out why this error is occurring.

👉 Solution

We have an error because we are attempting to index into the productPrices object with a string.

Let’s break the error down.

The “implicit ‘any’” part of the error message is TypeScript telling us it does not know what type the type is supposed to be.

For the “index” part of the error message, we need to remember that indexing means accessing an object using dot notation or dynamic string notation.

When typing productPrices followed by a . or [], TypeScript suggests autocompletion for one of the three possible keys: Apple, Banana, or Orange.

The three possible values are like an index signature for how the object can be called.

There are a few ways we can update productPrices to resolve this error:

1️⃣ Use a Record

One option is to update productPrices to use a Record type where the index is a string, followed by a number:

const productPrices: Record<string, number> = {
Apple: 1.2,
Banana: 0.5,
Orange: 0.8,
}

With this Record setup, we could pass in any string to index into the object whether it exists in productPrices or not.

2️⃣ Error in the Function

Another option is to update the getPrice function to use a union type for the productName parameter to ensure the function only accepts specific product names:

const getPrice = (productName: "Apple" | "Banana" | "Orange") => {
return productPrices[productName];
}

getPrice("Pear"); // red squiggly line under "Pear"

With this change, calling getPrice with an invalid product name will result in a TypeScript error.

3️⃣ Using keyof typeof

A third option is to use keyof typeof to get the type of the productPrices object and use that as the type for the productName parameter:

const getPrice = (productName: keyof typeof productPrices) => {
return productPrices[productName];
}

Using keyof typeof is a good option because it ensures that the productName parameter is always a valid key for the productPrices object.

When hovering over the call to getPrice, we can see that it expects a value of type “Apple” | “Banana” | “Orange”:

getPrice("Pear") // red squiggly line under "Pear"

// hovering over getPrice shows:
getPrice: (productName: "Apple" | "Banana" | "Orange") => number;

4️⃣ Casting

With casting we can cheat the type system and bypass the TypeScript error.

Assuming we know the productName will definitely be one of Apple, Banana, or Orange, we can use casting to bypass the TypeScript error.

To do this, we will use keyof typeof inside the actual indexing:

const getPrice = (productName: string) => {
return productPrices[productName as keyof typeof productPrices]
}

The best thing you should do in this situation is to provide proper types to your variables and functions. 🚀

I hope you found it useful. Thanks for reading. 🙏

Let’s get connected! You can find me on:

--

--