Quick answer
You indexed an object with a dynamic string key but its type has no index signature, so the result would be an implicit any. If the key is one of the object's own keys, type it as keyof typeof obj. For a dictionary, use a Record / index signature (Record<string, T>) or a real Map.
The exact error string
const colors = { red: "#f00", green: "#0f0" };
const key: string = "red";
colors[key];
// error TS7053: Element implicitly has an 'any' type because expression
// of type 'string' can't be used to index type '{ red: string; green: string; }'.
// No index signature with a parameter of type 'string' was found.
How to diagnose it
The question is whether the object has a fixed set of keys or is a dictionary — that decides the fix:
- Fixed keys (a lookup table, a config object) and the key is one of them →
keyof typeof obj(Fix 1) keeps each value's type. - Arbitrary string keys (counts, caches, form state) →
Record<string, T>/ index signature (Fix 2). - Key comes from
Object.keys→ it'sstring, so cast it (Fix 3). - Keys are fully dynamic or non-string → a
Map(Fix 4).
Fix 1: key is one of the object's keys → keyof typeof
const key = "red" as keyof typeof colors; // "red" | "green"
colors[key]; // ✅ typed as string
function pick(k: keyof typeof colors) { return colors[k]; }
Fix 2: it's a dictionary → index signature / Record
const counts: Record<string, number> = {};
counts["apples"] = 3; // ✅ any string key -> number
interface Counts { [key: string]: number; } // equivalent index signature
Fix 3: Object.keys loops
Object.keys(colors).forEach((k) => {
const key = k as keyof typeof colors;
console.log(colors[key]); // ✅
});
Fix 4: truly dynamic data → Map
const m = new Map<string, number>();
m.set("apples", 3);
m.get("apples"); // number | undefined
Worked example: indexing a parsed JSON dictionary
A config or i18n file is loaded as JSON and looked up by a runtime key. Untyped, the lookup is an implicit any; type it as a Record and the access is checked:
const messages = JSON.parse(text); // any
messages[userLocale]; // unchecked
// type it as a dictionary:
const messages2: Record<string, string> = JSON.parse(text);
const msg = messages2[userLocale] ?? messages2["en"]; // ✅ string
For a fixed-shape config object, generate an interface from a sample with JSON to TypeScript and index with keyof typeof so misspelled keys are still caught.
TS7053 in React
// 1) a theme/styles lookup by a dynamic variant
const styles = { primary: "...", danger: "..." };
function Button({ variant }: { variant: keyof typeof styles }) {
return <button className={styles[variant]} />; // ✅ variant is a known key
}
// 2) controlled form state keyed by the input name
const [form, setForm] = useState<Record<string, string>>({});
const onChange = (e: React.ChangeEvent<HTMLInputElement>) =>
setForm(f => ({ ...f, [e.target.name]: e.target.value })); // ✅ Record key
Common variants of this message
| Situation | Cause | Fix |
|---|---|---|
| key is a known property | string vs fixed keys | as keyof typeof obj |
| dictionary object | no index signature | Record<string, T> |
Object.keys(obj).forEach | keys() returns string[] | cast each key |
| enum/number key | numeric index expression | keyof or numeric index signature |
| fully dynamic key/value | runtime-built map | Map<K, V> |
Debugging checklist
- ✓ Fixed keys + key is one of them? Type it
as keyof typeof obj - ✓ Dictionary? Use
Record<string, T>/ an index signature - ✓ Looping
Object.keys? Cast each key tokeyof typeof obj - ✓ Fully dynamic key/value? Consider a
Map<string, T> - ✓ React form/theme? Key the state
Recordor constrain the prop tokeyof - ✓ From JSON? Type it (Record or generated interface) before indexing
- ✓ Avoid
as any— it drops checking on the result
Frequently Asked Questions
When should I use keyof typeof versus Record?
Use keyof typeof when the key is guaranteed to be one of a fixed object's own keys — it keeps each value's specific type. Use Record<string, T> (or an index signature) when the object is a dictionary with arbitrary string keys. keyof preserves precision; Record accepts any key.
Why does Object.keys(obj).forEach trigger TS7053?
Object.keys is typed to return string[], not (keyof typeof obj)[], because an object can have extra keys at runtime. So using each string key to index the object is a dynamic access. Cast the key inside the loop: const k = key as keyof typeof obj.
Does adding an index signature weaken my types?
Somewhat: with { [k: string]: T } TypeScript will allow any string key and won't flag typos, and (with noUncheckedIndexedAccess) results become T | undefined. For a true dictionary that's correct; for a fixed-shape object, prefer keyof typeof so misspelled keys are still caught.
When is a Map better than an indexed object?
When keys are genuinely dynamic, added/removed at runtime, or not strings (numbers, objects). Map<K, V> gives get/set/has with clean typing and no index-signature workarounds, and .get() returns V | undefined so you handle misses explicitly.
Why does enabling a flag suddenly cause TS7053?
TS7053 is gated by noImplicitAny (part of strict). Turning on strict mode surfaces previously-silent implicit-any index accesses. That's the check working — add the keyof/Record typing rather than disabling noImplicitAny.
Can I index a JSON object without losing type safety?
Yes. If it's a dictionary, type the parsed value as Record<string, T>. If it has fixed keys, generate an interface from a sample and index with keyof typeof. Either way the parsed value gets a real type, so the index access is checked instead of any.
Typing a JSON object?
Generate a Record or interface from a real payload with JSON to TypeScript — nothing is uploaded to a server.