'TypeScript map over Object keys and values: Element implicitly has an 'any' type

I am trying to iterate over object keys and values but TypeScript is shouting at me that:

Element implicitly has an any type because of type string can't be used to index type { name: string; surname: string; gender: string; }

What am I doing wrong?

const DATA = {
  name: "John",
  surname: "Smith",
  gender: "Male"
}

const result = Object.keys(DATA).map((d: string) => `${d} - ${DATA[d]}`)

Here is a screenshot of the error:

screenshot of typescript error



Solution 1:[1]

Just cast the string returned from the Object.keys into the key of the Data object.

const DATA = {
  name: "John",
  surname: "Smith",
  gender: "Male"
}

const result = Object.keys(DATA).map((d: string) => `${d} - ${DATA[d as keyof typeof DATA]}`)

Playground Link

Solution 2:[2]

Error

Element implicitly has an any type because expression of type string can't be used to index type {name: string; surname: string; gender: string; }.

No index signature with a parameter of type string was found on type ...

Solution 1: Define object as Record type

const DataRecord: Record<string, string> = {
  name: "Johnny-come-lately",
  surname: "Smithers",
  gender: "Male"
}

for (const key of Object.keys(DataRecord)) {
  console.log(`${key}: ${DataRecord[key]}`);
}

Solution 2: Define object as an Indexable Type

const DataIndexableType: {[key: string]: string} = {
  name: "Johnny-come-lately",
  surname: "Smithers",
  gender: "Male"
}

for (const key of Object.keys(DataIndexableType)) {
  console.log(`${key}: ${DataIndexableType[key]}`);
}

Solution 3: Use Object.entries()

If for some reason it is not practical to add type information for the object, Object.entries() may be used without using type casting.

const DATA = {
  name: "John",
  surname: "Smith",
  gender: "Male"
}

// Object.entries
for (const [key, value] of Object.entries(DATA)) {
    console.log(`${key}: ${value}`);
}

// Or Object.entries.map
Object.entries(DATA).map( ([key, value]) => console.log(`${key}: ${value}`));

Solution 4: Use a typecast on the keys

const DATA = {
  name: "John",
  surname: "Smith",
  gender: "Male"
}

// Object.keys with typecast on key.
for (const key of Object.keys(DATA)) {
  console.log(`${key}: ${DATA[key as keyof typeof DATA]}`);
}

Solution 5: Use a typecast on the object indicating indexability

const DATA = {
  name: "John",
  surname: "Smith",
  gender: "Male"
}

// Object.keys with typecast on object.
for (const key of Object.keys(DATA)) {
  console.log(`${key}: ${(DATA as {[key: string]: string})[key]}`);
}

Solution 3:[3]

You need to tell typescript that the keys of your object are of type string.

const DATA: {[key: string]: string} = {
  name: "John",
  surname: "Smith",
  gender: "Male"
}

const result = Object.keys(DATA).map((d: string) => `${d} - ${DATA[d]}`)

Solution 4:[4]

The Object's keys themselves are not explicitly typed as strings.

When you do

Object.keys(DATA)

You're getting name, surname, gender as values to pass to map, not John, Smith, Male.

To type the keys as well you need to type the object like this:

type DataType = {[key:string]: string }
const DATA:DataType = 
{
 name: "John",
 surname: "Smith",
 gender: "Male"
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Christopher Peisert
Solution 3 Reyno
Solution 4 SJT