Home > Back-end >  Why does this reducer function not work in a typescript class and can I make it work?
Why does this reducer function not work in a typescript class and can I make it work?

Time:12-03

I've been playing around with reducers in this years's first advent of code challenge, and this code works fine:

export default class CalorieCounter {
  public static calculateMaxInventoryValue(elfInventories: number[][]): number {
    const sumInventoriesReducer = (
      acc: number[],
      element: number[]
    ): number[] => [...acc, this.sumCalories(element)];

    return Math.max(...elfInventories.reduce(sumInventoriesReducer, []));
  }

  private static sumCalories(inventory: number[]): number {
    return inventory.reduce((a: number, b: number) => a   b, 0);
  }
}

I then tried to split out the sumInventoriesReducer into it's own private function in the same class. This code does not work:

export default class CalorieCounter {
  public static calculateMaxInventoryValue(elfInventories: number[][]): number {
    return Math.max(...elfInventories.reduce(this.sumInventoriesReducer, []));
  }

  private static sumInventoriesReducer(
    acc: number[],
    element: number[]
  ): number[] {
    return [...acc, this.sumCalories(element)];
  }

  private static sumCalories(inventory: number[]): number {
    return inventory.reduce((a: number, b: number) => a   b, 0);
  }
}

The logic is exactly the same, all that's changed is that it's passed in as a private function (the fact that it's static isn't the reason, tried it without static and got the same error).

This is the error:

 TypeError: Cannot read property 'sumCalories' of undefined

      20 |     element: number[]
      21 |   ): number[] {
    > 22 |     return [...acc, this.sumCalories(element)];
         |                          ^
      23 |   }
      24 |
      25 |   private static sumCalories(inventory: number[]): number {

I want to do this in an OOP way if I can, aware reducers are a staple of functional programming but I feel like I should be able to get this work using a private class function. Can anyone help?

CodePudding user response:

The problem is that you're trying to access an instance property (that exist only after constructor() has been called) in a static method (that exists only on the class and not on the prototype).

After a constructor() method has been called the keyword this has the value of the instance object, but if you reference this in a static method you're referencing an undefined variable since to access a static method you don't call a constructor method

export default class CalorieCounter {
  public static calculateMaxInventoryValue(elfInventories: number[][]): number {
    return Math.max(...elfInventories.reduce(this.sumInventoriesReducer, []));
  }

  private static sumInventoriesReducer(
    acc: number[],
    element: number[]
  ): number[] {
    return [...acc, this.sumCalories(element)]; // The problem is here
  }

  private static sumCalories(inventory: number[]): number {
    return inventory.reduce((a: number, b: number) => a   b, 0);
  }
}

If you want to keep this schema you can just update that line so it would go

  • from: this.sumCalories(element)
  • to: CalorieCounter.sumCalories(element) By doing so, you're accessing the method from the class itself and not from a non-existing instance.

The resulting code would be:

export default class CalorieCounter {
  public static calculateMaxInventoryValue(elfInventories: number[][]): number {
    return Math.max(...elfInventories.reduce(this.sumInventoriesReducer, []));
  }

  private static sumInventoriesReducer(
    acc: number[],
    element: number[]
  ): number[] {
    return [...acc, CalorieCounter.sumCalories(element)]; // The problem is here
  }

  private static sumCalories(inventory: number[]): number {
    return inventory.reduce((a: number, b: number) => a   b, 0);
  }
}

Same as above, also the calculateMaxInventoryValue method is static but tries to access an instance method, by correcting it the code would become:

export default class CalorieCounter {
  public static calculateMaxInventoryValue(elfInventories: number[][]): number {
    return Math.max(...elfInventories.reduce(CalorieCounter.sumInventoriesReducer, []));
  }

  private static sumInventoriesReducer(
    acc: number[],
    element: number[]
  ): number[] {
    return [...acc, CalorieCounter.sumCalories(element)]; // The problem is here
  }

  private static sumCalories(inventory: number[]): number {
    return inventory.reduce((a: number, b: number) => a   b, 0);
  }
}

CodePudding user response:

This is because you don't flatten this.sumCalories(element).

this.sumCalories(element) returns a number[], so you need to flatten this with the three dots.

If you write return [...acc, ...this.sumCalories(element)]; it should work.

  • Related