Manzana
Manzana

Reputation: 159

How can I define Array.reduce method in Typescript?

I have a problem with the reduce method in TypeScript:

const items = {a: 10, b:20, c: 30}
const itemsTotal = Object.keys(items).reduce((accumulator: number, key: keyof typeof items ) => {
    return accumulator + items[key]
  }, 0)

I keep receiving the Typescript error:

Argument of type '(accumulator: number, key: "a" | "b" | "c") => number' is not assignable to parameter of type '(previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string'.

Types of parameters 'accumulator' and 'previousValue' are incompatible.***

It seems that I need to define the type of the reduce method, but how?

Upvotes: 1

Views: 1154

Answers (3)

Miroslav Popov
Miroslav Popov

Reputation: 3383

Define your items as a Record of string to number. It will be clear for the reduce method that the item is a number.

const items: Record<string, number> = {a: 10, b: 20, c: 30}

const itemsTotal = Object.keys(items).reduce((accumulator: number, key: string) => {
    return accumulator + items[key];
}, 0)

You can also skip the braces in the reduce body.

Object.keys(items).reduce((acc: number, key: string) => acc + items[key], 0)

Even more, you can skip the type designations in the reduce because your items are already defined as numbers in the Record.

Object.keys(items).reduce((acc, key) => acc + items[key], 0)

Edit

You can skip the accumulator initialization. reduce starts from the first item in such a case.

Object.values(items).reduce( (acc, item) => acc + item )

The fastest solution is with for of because there are no function calls:

let sum = 0
for (const item of Object.values(items)) {
   sum += item;
}

Upvotes: 1

T.J. Crowder
T.J. Crowder

Reputation: 1074138

Object.keys returns a string[], so you can't apply a reducer function that expects a keyof typeof items to it.

You could use a type assertion, since you know it's valid:

const items = {a: 10, b:20, c: 30};
const itemsTotal = Object.keys(items).reduce((accumulator, key) => {
    return accumulator + items[key as keyof typeof items];
}, 0);

Playground

...but you don't need the key anyway, just use Object.values:

const items = {a: 10, b:20, c: 30};
const itemsTotal = Object.values(items).reduce((accumulator, value) => {
    return accumulator + value;
}, 0);

Playground

(But frankly I'd just use a simple loop.)

Upvotes: 2

Drag13
Drag13

Reputation: 5988

Not the cleanest solution but you can use this snippet:

const items = { a: 10, b: 20, c: 30 }
const itemsTotal = Object.keys(items).reduce((accumulator, key) => {
    return accumulator + items[key as keyof typeof items]
}, 0)

Key point is to cast key to keyof typeof items

Upvotes: 1

Related Questions