10

In plain JavaScript we can iterate over object props and values like so:

const values = Object.keys(obj).map(key => obj[key]);

In TypeScript this syntax is wrong because the TS compiler is displaying the following message:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type Object.

Is there an alternative way not using Map<string, T> to do it and get the value of each key?

I encountered this problem while building an app using React and TS and I have in my state an object which I need to do something like this:

const stateJSX: HTMLParagraphElement[] = Object.keys(obj).map(key => <p>`${key}: ${obj[key]}`<p>);
Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
Ori Kain
  • 128
  • 1
  • 1
  • 7

4 Answers4

7

You can easily use it with some help of keyof operator:

const test = <T extends Record<string, unknown>>(obj: T) => {
 return (Object.keys(obj) as Array<keyof T>).map(key => obj[key])
}

You should asure TS, that key variable could be used as index for obj argument

  • 2
    You may want to note that `Object.keys()` does not return `Array` automatically because [it is not generally safe to do so](https://stackoverflow.com/questions/55012174/why-doesnt-object-keys-return-a-keyof-type-in-typescript) – jcalz Dec 20 '20 at 01:24
  • 1
    @jcalz , yes You are right. I have read related github issue. It is better to use with immutable objects. Btw, do you now the better way to use Object.keys with TS? I know, we can do it with typeguards inside map function, but I think it is a bit overhead – captain-yossarian from Ukraine Dec 20 '20 at 10:05
  • 1
    This is the only answer that actually discusses how to do this in TypeScript. – dangerginger Jul 07 '22 at 22:31
6

Use Object.entries to iterate over both the keys and the values:

Object.entries(obj).map(([key, value]) => `${key}: ${value}`)
Aplet123
  • 33,825
  • 1
  • 29
  • 55
6

Object.keys()

To use Object.keys(), (as indicated in the original question), you can add a typecast indicating that the object is an indexable type:

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

Or use a typecast on the key:

for (const key of Object.keys(obj)) {
  console.log(`${key}: ${obj[key as keyof typeof obj]}`);
}

Object.entries()

Object.entries() may be used without map() as follows:

for (const [key, value] of Object.entries(obj)) {
    console.log(`${key}: ${value}`);
}
Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
3

Use Object.entries

Object.entries(obj).forEach(([key, value]) => console.log(`${key}: ${value}`))
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Gibin Jose
  • 55
  • 3
  • 3
    This answer is really near to [this](https://stackoverflow.com/a/65375054/10952503) and [this](https://stackoverflow.com/a/69757191/10952503) – Elikill58 Feb 01 '22 at 08:31