Home > Back-end >  Property 'forEach' does not exist on type 'Foo' - when iterating through Object.
Property 'forEach' does not exist on type 'Foo' - when iterating through Object.

Time:07-21

I'm not sure what I am missing in the code below to stop getting the error that says that the forEach method doesn't exist.

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);
        });
      }
    });
};

And this code returns no error:

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

So I found out that this would work but was not sure how good this solution is?

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

CodePudding user response:

TypeScript does not narrow down properties of variables - it only narrows variables themselves (unions). Doing

if (Array.isArray(data[key])) {

tests a property of a variable, but not a variable itself, which is why the above fails and, as you saw, if (Array.isArray(value)) { succeeds.

While you could fix it by putting the value at the key into a standalone variable first:

const bar = (data: FooCollection) => {
  Object.keys(data)
    .forEach((key) => {
      const value = data[key];
      if (Array.isArray(value)) {
        // do stuff with value

A better approach would be to skip the key altogether, because it looks like you only care about the values.

const bar = (data: FooCollection) => {
  Object.values(data)
    .forEach((value) => {
      if (Array.isArray(value)) {
        // do stuff with value

If you do need to do stuff with the key as well as the value, use Object.entries to get both at once.

const bar = (data: FooCollection) => {
  Object.entries(data)
    .forEach(([key, value]) => {
      if (Array.isArray(value)) {
        // do stuff with key and value
  • Related