suyeon
suyeon

Reputation: 131

How to fix typescript error in redux-toolkit?

I'm doing a redux-toolkit tutorial with typescript. But I'm a typescript beginner.

I don't know what the problem is here. Please give me your insight.

This is an error message. : TS2322: Type 'number' is not assignable to type 'void | State | WritableDraft'.

import {CaseReducer, createSlice, PayloadAction} from "@reduxjs/toolkit";

type State = {
  value: number
}
const increment: CaseReducer<State,PayloadAction<number>> = (state, action) => state.value + action.payload; // error line

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0
  },
  reducers: {
    increment,
    decrement: state => {
      state.value -= 1
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload
    },
  },
})

export const {increment, decrement, incrementByAmount} = counterSlice.actions;

export default counterSlice.reducer;

Upvotes: 10

Views: 26113

Answers (3)

Jokanola
Jokanola

Reputation: 88

I resolved this by updating my typescript version to recommended version

Upvotes: 0

Linda Paiste
Linda Paiste

Reputation: 42188

An arrow function without curly braces around it is an implied return. So you are returning state.value + action.payload which is a number.

Redux Toolkit allows you to either return a new state (type State | WritableDraft<State> at the time of this answer, or type State | Draft<State> in newer versions of RTK) or modify the draft state and not return anything (type void). You get a Typescript error because returning number is neither or these.

You likely want to modify the draft state, so you need curly braces around your function body so that you aren't returning anything.


These three functions are all valid. Ordered from least to most verbose:

  1. You can increment the value directly using the addition assignment operator +=
const increment: CaseReducer<State,PayloadAction<number>> = (state, action) => {
  state.value += action.payload;
}
  1. You can assign a new value to the state.value property with assignment operator =
const increment: CaseReducer<State,PayloadAction<number>> = (state, action) => {
  state.value = state.value + action.payload;
}
  1. (Not recommended) You can return an entirely new state. I am using parentheses around curly braces to return an object with the property value.
const increment: CaseReducer<State,PayloadAction<number>> = (state, action) => ({
  value: state.value + action.payload
});

If there were properties other than value you would need to copy them like {...state, value: newValue } which is what you see in traditional Redux reducers. Redux Toolkit makes options 1 and 2 available so that you don't have to do this. But if you chose to return a new state then it must be a complete state.

Upvotes: 10

NearHuscarl
NearHuscarl

Reputation: 81370

CaseReducer return value must be void | State | WritableDraft while your expression:

(state, action) => state.value + action.payload

Is a function that returns a number. The solution is to add the void operator before the return value to set it to undefined.

(state, action) => void (state.value += action.payload)

Upvotes: 0

Related Questions