Borislav Hadzhiev
Sun Feb 27 2022·2 min read
Photo by Toa Heftiba
To iterate over an object with forEach()
in TypeScript:
Object.entries()
method to get an array of key-value pairs.forEach()
method on the array.forEach()
method will get called with an array containing a key-value
pair on each iteration.const obj = { name: 'Tom', country: 'Chile', }; // ✅ forEach after Object.keys (Object.keys(obj) as (keyof typeof obj)[]).forEach((key, index) => { // 👇️ name Tom 0, country Chile 1 console.log(key, obj[key], index); }); // ✅ forEach after Object.entries (better) Object.entries(obj).forEach(([key, value], index) => { // 👇️ name Tom 0, country Chile 1 console.log(key, value, index); });
In the first example, we used the Object.keys method to get an array of the object's keys.
However, TypeScript sets the type of the return value of Object.keys()
to
string[]
.
const obj = { name: 'Tom', country: 'Chile', }; // 👇️ string[] const result = Object.keys(obj); console.log(Object.keys(obj)); // 👉️ ['name', 'country']
Since not every string is a key in the object, we have to type the return value
of Object.keys()
before we are able to access object values by key.
We used
keyof typeof
to set the type of Object.keys()
to an array containing keys of obj
, so we
can safely access its values.
const obj = { name: 'Tom', country: 'Chile', }; // ✅ forEach after Object.keys (Object.keys(obj) as (keyof typeof obj)[]).forEach((key, index) => { // 👇️ name Tom 0, country Chile 1 console.log(key, obj[key], index); });
Had we not used the type assertion, we would get an error when trying to access a value in the object by key.
const obj = { name: 'Tom', country: 'Chile', }; Object.keys(obj).forEach((key, index) => { // ⛔️ Error: No index signature with a parameter // of type 'string' was found on // type '{ name: string; country: string; }'. console.log(key, obj[key], index); });
TypeScript is telling us that key
has a type of string
and the object only
has keys name
and country
, so we can't use any string
to index the object.
A much cleaner approach is to use the Object.entries method.
const obj = { name: 'Tom', country: 'Chile', }; // ✅ forEach after Object.entries Object.entries(obj).forEach(([key, value], index) => { // 👇️ name Tom 0, country Chile 1 console.log(key, value, index); });
The Object.entries()
method returns an array of key-value pairs, on which we
can call the forEach()
method.
const obj = { name: 'Tom', country: 'Chile', }; // 👇️ const result: [string, string][] const result = Object.entries(obj); // 👇️ [['name', 'Tom'], ['country', 'Chile']] console.log(result);
The forEach
method gets passed an array containing 2
elements on each
iteration - the key and the value.
We can use destructuring to get the key and value directly.
const obj = { name: 'Tom', country: 'Chile', }; // ✅ forEach after Object.entries Object.entries(obj).forEach(([key, value], index) => { // 👇️ name Tom 0, country Chile 1 console.log(key, value, index); });
We used destructuring assignment in the function's parameter list.
This is very similar to the following line of code.
const [key, value] = ['name', 'Tom']; console.log(key); // 👉️ "name" console.log(value); // 👉️ "Tom"
We are basically assigning the array elements to variables (the order is preserved).