Skip to main content
TS2538

Type 'X' cannot be used as an index type.

You indexed an object with something that is not a string, number or symbol.

What it means

JavaScript object keys can only be strings or symbols (numbers are coerced to strings). So an index expression must be typed string, number, symbol, or a literal union of those. Anything else — an object, an array, undefined, a union that includes them — is rejected.

The most frequent real cause is a value that is nearly a valid key: string | undefined from an optional property or an array.find(). The fix is to narrow away the invalid half, not to cast.

Reproduce it

declare const key: { a: 1 };
declare const obj: Record<string, number>;
console.log(obj[key]);
//              ~~~ Type '{ a: 1; }' cannot be used as an index type.

How to fix it

Narrow away undefined

The key comes from an optional field or a lookup that may fail — by far the most common cause.

Before
const key = form.name; // string | undefined
const value = table[key];
After
const key = form.name;
const value = key ? table[key] : undefined;

Index with the right property

You passed the whole object where you meant one of its fields. The compiler is pointing at a real mistake.

Before
console.log(scores[user]);
After
console.log(scores[user.id]);

Type the key as a union of allowed keys

Only certain keys are valid. keyof makes that explicit and gives you autocomplete plus a compile error on typos.

Before
function get(o: Config, k: string) { return o[k]; }
After
function get<K extends keyof Config>(o: Config, k: K) { return o[k]; }

Suppressing it

Casting the key with as string compiles but can produce undefined at runtime when the value really was missing. Narrowing costs one line and removes the risk.

Related errors

Hitting this while migrating to TypeScript?

Convert JavaScript to TypeScript deterministically — imports rewritten, JSDoc promoted to real types, class fields declared. No guessed types.

Open the converter