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.
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.
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!
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.
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.
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 }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With