12

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

5 Answers 5

20

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]}`);
}
Sign up to request clarification or add additional context in comments.

Comments

9

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

4 Comments

I think it's better practice to type the object correctly rather than cast in the middle of a function
What you've done is just removed the type of keys DATA can have, it loses the type that way, you can never tell what keys DATA have if you just make its type Record<string, string>, what I have done, is maintained the type DATA had.
Right, that makes sense. But what other types could a key have in an object?
I am marking this as correct answer since it looks like the cleanest solution to my problem syntax-wise. Thank you for helping out guys.
2

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]}`)

Comments

0

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"
}

Comments

0

You should cast the result of Object.keys(DATA) to (keyof typeof DATA)[] since Object.keys by default returns string[].

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

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

Also, make sure you don't cast the iterating variable d to string. By not casting it to string, its type will be automatically inferred.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.