Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript and Redux: Why do I need to add ` | undefined` to my Reducer state type?

Why can I not just type my reducer simply like this, without adding " | undefined" to my redux state type?

const reducer: Reducer<ReduxState> = function(state: ReduxState, action: any) ...

Extra context::::

This works OK:

export const reducer: Reducer<ReduxState | undefined> = function (
    state: ReduxState | undefined, 
    action: any
) {
    return state
}
export default reducer

However, it doesnt when taking away state parameter "undefined" from fxn:

export const reducer: Reducer<ReduxState | undefined> = function (
    state: ReduxState, 
    action: any
) {
    return state
}
export default reducer

Which gives an error of:

Type '(state: ReduxState, action: any) => ReduxState' is not assignable to type 'Reducer<ReduxState | undefined, AnyAction>'.
  Types of parameters 'state' and 'state' are incompatible.
    Type 'ReduxState | undefined' is not assignable to type 'ReduxState'.
      Type 'undefined' is not assignable to type 'ReduxState'.ts(2322)

Or this:

export const reducer: Reducer<ReduxState> = function (
    state: ReduxState | undefined, 
    action: any
) {
    return state
}
export default reducer

which gives an error msg of:

Type '(state: ReduxState | undefined, action: any) => ReduxState | undefined' is not assignable to type 'Reducer<ReduxState, AnyAction>'.
  Type 'ReduxState | undefined' is not assignable to type 'ReduxState'.
    Type 'undefined' is not assignable to type 'ReduxState'.ts(2322)

And lastly, this doesn't work either:

import {ReduxState, ReduxAction, ReduxActionType} from './types'
import {Reducer} from 'redux'

export const reducer: Reducer<ReduxState> = function (
    state: ReduxState, 
    action: any
) {
    return state
}
export default reducer

With an error msg of :

Type '(state: ReduxState, action: any) => ReduxState' is not assignable to type 'Reducer<ReduxState, AnyAction>'. Types of parameters 'state' and 'state' are incompatible. Type 'ReduxState | undefined' is not assignable to type 'ReduxState'. Type 'undefined' is not assignable to type 'ReduxState'.ts(2322)

TL; DR: Typescript isn't happy with my Reducer unless I specifically allow "ReduxState | undefined" type in both the Reducer<ReduxState|undefined> and function(state: ReduxState | undefined).

like image 752
jf1234 Avatar asked Apr 22 '19 17:04

jf1234


People also ask

Can you use TypeScript with Redux?

We strongly recommend using TypeScript in Redux applications. However, like all tools, TypeScript has tradeoffs. It adds complexity in terms of writing additional code, understanding TS syntax, and building the application.

Can we update state in reducer?

The state is updated and managed by reducers. Reducers always have to return something even if it's null ; they should never return undefined . If a reducer's state is an object, you must always return a new object instead of editing the object in place.

Can I use state with Redux?

It is totally fine to use a mix of React component state and Redux state. You might for example use non-critical UI state inside React components, like if a checkbox is checked or not. The official Redux FAQ has a good list of rules of thumb for determining what kind of data should put into Redux.


1 Answers

Because for the initial state, the previous state is undefined. Therefore your function has to be able to deal with state being undefined, thats what the first error tells you.

The second version doesn't work, because you return state, and that can be undefined (as you don't check if it is not defined), and therefore the return type of that function (which is the generic argument to Reducer) also have to be possible undefined. You could guard against that:

  if(state === undefined)
     return { /*...*/ };
  else return state;

then Reducer<ReduxState> would describe the type correctly.

like image 126
Jonas Wilms Avatar answered Nov 17 '22 04:11

Jonas Wilms