Error: Trying to iterate through Object.keys() on type 'Foo' does not support the property 'forEach'

I'm struggling to figure out a solution for the error message that keeps popping up, indicating that the forEach method is not accessible in the code snippet below.

type Foo = Array<string> | string;

type FooCollection = { [key: string]: Foo }

const bar = (data: FooCollection) => {
  Object.keys(data)
    .forEach((key) => {
      if (Array.isArray(data[key])) {
        // this forEach is disputed
        data[key].forEach((v, i) => {
          console.log(v, i);
        });
      }
    });
};

The following code, however, runs without any errors:

const baz = (value: Foo) => {
  if (Array.isArray(value)) {
    value.forEach((v, i) => {
      console.log(v, i);
    });
  }
};

After some investigation, I discovered a potential workaround but I am unsure about its effectiveness. Here's the modified snippet:

const qux = (data: FooCollection) => {
  Object.keys(data)
    .forEach((key) => {
      if (Array.isArray(data[key])) {
        baz(data[key]);
      } else {
        // ...
      }
    });
};

Answer №1

When working with TypeScript, it's important to note that narrowing down properties of variables is not supported - the narrowing only applies to the variables themselves (unions). This is why using if (Array.isArray(data[key])) may not work as expected, since it tests a property of the variable rather than the variable itself. On the other hand, if (Array.isArray(value)) succeeds because it checks the variable directly.

To resolve this issue, one approach is to store the value of the key in a separate variable before performing any checks:

const bar = (data: FooCollection) => {
  Object.keys(data)
    .forEach((key) => {
      const value = data[key];
      if (Array.isArray(value)) {
        // perform actions on value

Alternatively, a more streamlined solution would be to focus solely on the values without considering the keys:

const bar = (data: FooCollection) => {
  Object.values(data)
    .forEach((value) => {
      if (Array.isArray(value)) {
        // perform actions on value

If handling both the key and value is necessary, you can use Object.entries to access both simultaneously:

const bar = (data: FooCollection) => {
  Object.entries(data)
    .forEach(([key, value]) => {
      if (Array.isArray(value)) {
        // perform actions on key and value

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for creating a versatile function in TypeScript that accepts either a single value or an array of values for two parameters

I'm currently working on a task to develop a versatile function that accepts a parameter called hashMapName, another parameter called 'keys' which can be either a string or an array of strings, and a callback function that will return either ...

What is the best way to prevent a font awesome icon from appearing in a span during data loading

I am currently working on an Angular 11 application where I have implemented an icon to trigger the loading of a graph. However, I have noticed that there is a delay in loading the graph when the icon is clicked. To prevent users from triggering the icon m ...

Create a custom validation function that accepts additional parameters

At the moment, I have implemented the following code but I haven't utilized the extra data yet. create-room.component.ts import { Component, Inject, OnInit } from '@angular/core'; import { AbstractControl, FormBuilder, FormControl, FormGroup ...

Tips for simulating difficult private attributes within a class during unit testing in TypeScript

Is there a way to mock the value of a hard private property in a unit test? For example, how can I expect something like expect(event.getEventHis()).toBeEqual(['a', 'b']) export class EventController { #event: []; constructor() { ...

What is the best way to specify a function parameter as a Function type in TypeScript?

I'm currently delving into the world of TypeScript and I am unsure about how to specify a function parameter as a function type. For instance, in this piece of code, I am passing a setState function through props to a child component. const SelectCity ...

Exploring the Applications of Directives in Multiple Modules within Angular 2

When I declare the directive in two modules, I get an error that says Type PermissionDirective is part of the declarations of 2 modules. However, when I declare it in only one module, I receive an error stating Can't bind to 'isPermission' s ...

Strategies for preventing multi-level inheritance of TypeScript class properties and methods

In my current JavaScript class structure, the DataService is defined as follows: // data.service.ts export class DataService { public url = environment.url; constructor( private uri: string, private httpClient: HttpClient, ) { } ...

How the addition of a type union allows it to be assigned to AnyAction

Struggling with Redux code, I've encountered a peculiar behavior regarding type assignment that has left me puzzled. In the following code snippet, it's clear that you cannot assign anyaction to iaction. Yet, surprisingly, assigning anyaction to ...

Tips for maintaining a marker at the bottom of the screen while zooming, similar to Google Maps

Is there a way to customize the zoom behavior in my project? I want to maintain the bottom position while resizing the other three directions, and also include pitch adjustments. https://i.sstatic.net/hQdg8.gif https://i.sstatic.net/m3xef.gif I aim for t ...

Ways to store a component in cache once its route is triggered

There are 3 components in my project: 1 parent and 2 child components with router outlet. The child component becomes active whenever its route is called, sharing data using a service. Both of these child components have complex views. When switching bet ...

Idea fails to detect imports

I have been attempting to use Angular2 in IntelliJ IDEA IDE. Although my code is valid (I have tried compiling and executing it), the IDE keeps showing me this error: https://i.stack.imgur.com/w6wIj.jpg Is there a way to configure IntelliJ IDEA to hide t ...

Backend images are failing to load

I'm facing an issue where the image I send from a nestjs backend to an angular frontend isn't displaying in the browser. https://i.sstatic.net/nicu4.png Here's how it works: I make a request from the frontend to the backend with the file p ...

Issue with Angular 2 Observable not triggering the complete function

I've been experimenting with the hero app tutorial for Angular 2 and currently have this Component set up: import { Component, OnInit } from '@angular/core' import { Subject } from 'rxjs/Subject'; import { Hero } from "./hero"; im ...

Can you explain how I can showcase JSON object values within an Angular framework?

After fetching data through a REST API in Angular, I need to display only the "classLevelPermissions" in table format as shown in the .html file. .ts - async getclp(className: string) { debugger; this.clplist = []; this.className = className ...

Factory Pattern Utilizing Enum for Field Population

Struggling to find a solution for setting default values for instances created by the factory method createLetterMap... I don't think the problem lies in 'How to loop over enums' because it seems impossible due to types not being available ...

What is the way to create a `Partial<T>` specifically for nullable fields?

I have a requirement for a custom Partial<T> type that can transform nullable fields into optional ones. Currently, I am focusing on typing our ORM, which converts undefined values to null for nullable fields. In particular, I want to modify a type ...

Guide to preserving canvas state in React?

I am currently working on a drawing application that allows users to draw lines on a canvas. The functionality is such that the line starts drawing on the first click, continues as the mouse moves, and stops on the second click. However, each time a user ...

Reduce the size of log messages in cypress

I am looking to shorten the cypress messages to a more concise string, for instance: Cypress log Transform to: -assert expected #buy-price-field to have value 17,169.00. Is there a way to achieve this? I have searched through the documentation but hav ...

Is it possible to limit the items in a TypeScript array to only accept shared IDs with items in another array?

I'm creating an object called ColumnAndColumnSettings with an index signature. The goal is to limit the values of columnSettings so that they only allow objects with IDs that are found in columns. type Column = { colId: string, width?: number, s ...

Tips for handling catch errors in fetch POST requests in React Native

I am facing an issue with handling errors when making a POST request in React Native. I understand that there is a catch block for network connection errors, but how can I handle errors received from the response when the username or password is incorrec ...