1

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?

3 Answers 3

2

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.)

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks T.J. both of your answers solved my problem. Kudoz to you
1

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

1 Comment

Great answer @Drag13, it solved my problem.
1

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

1 Comment

@Manzana, it is always a good idea to define your objects. Using Record<string, number> defines both the keys and the values.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.