error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ tea: number; coffee: number; cocoa: number; }'. is reported for object[key] when key is any string and the object's type only has a fixed set of properties. The checker cannot tell which property you get, so the result would be any.
It is one of the most common errors in JavaScript code that turns on strict: lookup tables indexed by a parameter, for...in loops, and event.target.name used as a key all produce it.
At a glance
| Code | TS7053 |
|---|---|
| Message | Element implicitly has an 'any' type because expression of type '{0}' can't be used to index type '{1}'. |
| TypeScript's category | error |
| Listed under | Implicit any |
| Turned on by | noImplicitAny, strict |
| In .js files | Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file |
The message is TypeScript's own text from its diagnostic messages file (Apache-2.0); {0} and {1} are filled in by tsc for each error.
What it looks like
const prices = { tea: 3, coffee: 4, cocoa: 4.5 };
/** @param {string} drink */
export function priceOf(drink) {
return prices[drink];error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ tea: number; coffee: number; cocoa: number; }'.
No index signature with a parameter of type 'string' was found on type '{ tea: number; coffee: number; cocoa: number; }'.
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} What causes it
- The key is typed
string(a parameter, afor...invariable, a form field name) and the object is an object literal or a@typedefwithout an index signature. noImplicitAnyis on (part ofstrict).
How to fix it
Narrow the key's type
If only the object's own keys are valid, say so: @param {keyof typeof prices} drink. Callers passing an arbitrary string are then reported where it matters. For a string from outside (a URL, a form), check it first with a type guard such as isDrink in the example, written with Object.hasOwn.
const prices = { tea: 3, coffee: 4, cocoa: 4.5 };
/** @param {keyof typeof prices} drink */
export function priceOf(drink) {
return prices[drink];
}
/** @type {Record<string, number | undefined>} */
const extras = { oatMilk: 0.5, syrup: 0.75 };
/** @param {string} name */
export function extraPrice(name) {
return extras[name] ?? 0;
}
/**
* @param {string} name
* @returns {name is keyof typeof prices}
*/
export function isDrink(name) {
return Object.hasOwn(prices, name);
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} Or give the object an index signature
If the object is a dictionary that any key may be looked up in, type it as one: /** @type {Record<string, number | undefined>} */. Including undefined makes the result honest for missing keys. A Map is the other good choice for open-ended keys.
Gotchas
if (key in prices)does not narrowkey, soprices[key]inside it is still TS7053; the type guard function is the JSDoc way to narrow it.- A cast on the key,
/** @type {keyof typeof prices} */ (key), also silences the error, without any check at run time.
Sources
- Keyof Type Operator · TypeScript handbook
- Object Types: Index Signatures · TypeScript handbook
- diagnosticMessages.json (TypeScript 5.9.3) · TypeScript on GitHub
Last reviewed 20 October 2026.