Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

useReducer's initialState is typed as never?

Tags:

initialState has the error: Argument of type '{ email: string; password: string; valid: boolean; }' is not assignable to parameter of type 'never'.ts(2345)

 function reducer(state: IState, action: IFluxAction) {   const Users = UsersFetch()   switch (action.type) {     case 'email':       const email = action.value       const valid = Users.find(e => e === email) ? true : false        return {         email,         valid,       }     case 'password':       const password = action.value       return {         password,       }     default:       throw new Error()   } } 
  const initialState = {     email: '',     password: '',     valid: false,   }   const [state, dispatch] = React.useReducer(reducer, initialState) 

What's the proper way of typing this to satisfy the error?

React 16.8.1 Typescript 3.3.1

Should be (is fixed by) adding ...state to the returns, like

  switch (action.type) {     case 'email':       const email = action.value       const valid = Users.find(e => e === email) ? true : false        return {         ...state,         email,         valid,       }     case 'password':       const password = action.value       return {         ...state,         password,       }     default:       throw new Error()   } 

Additionally - as suggested by @madflanderz , setting IState as the reducer's expected return value helps catch issues like this.

like image 462
Falieson Avatar asked Feb 19 '19 16:02

Falieson


People also ask

Why useReducer is used?

useReducer provides more predictable state transitions than useState , which becomes more important when state changes become so complex that you want to have one place to manage state, like the render function.

Is not assignable to parameter of type never Redux?

The error "Type is not assignable to type 'never'" occurs when we declare an empty state array with the useState hook but don't type the array. To solve the error, use a generic to type the state array, e.g. const [arr, setArr] = useState<string[]>([]) . Here is an example of how the error occurs. Copied!

What is a reducer in TypeScript?

So the action type should literally be any... Read more > Usage With TypeScript - Redux. Reducers are pure functions that receive the current state and incoming action as arguments, and return a new state.

Why use reducer in React?

Reducers are handy for creating small pools of isolated data contexts. You can use it in conjunction with React Context API to keep your state where it belongs.


2 Answers

I also struggled with this problem. The best way to prevent bugs seems to me to add the State Interface as the return type of the reducer. Then you see the type errors inside the reducer instead on the useReducer line.

like this:

function reducer(state: IState, action: IFluxAction): IState {    // reducer code    // type errors are visible here  } 
like image 113
madflanderz Avatar answered Sep 27 '22 18:09

madflanderz


The issue is most likely with your reducer's declaration. The initialState's type must be the same as the state's type and return value in the reducer function.

This will work:

function reducer(state: {email: string}) {   return state } const initialState = {   email: '', } const [state, dispatch] = React.useReducer(reducer, initialState) 

This will produce an error:

// state has a different type than initialState. function reducer(state: {address: string}) {   // No return statement. } const initialState = {   email: '', } const [state, dispatch] = React.useReducer(reducer, initialState) // Error 

In the React's typing you can see that the useReducer generic function always expects the initialState type to be of a ReducerState<R> type. The ReducerState<R> is a conditional type that tries to infer the proper state's type and falls back to never if it fails.

like image 39
Mateusz Kocz Avatar answered Sep 27 '22 20:09

Mateusz Kocz