question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

TypeScript definitions allow a reducer that doesn't handle all possible actions

See original GitHub issue

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

If the current behaviour is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar.

I’m using TypeScript and hit a situation where I managed to register my main reducer as only receiving my specific types of actions. This is a simplified version though somehow in my real case I managed to make the reducer not even need to accept undefined for the state: https://gist.github.com/Mossop/2871372747e55e0fedea64eb649067e6.

This compiles correctly with TypeScript because TypeScript thinks I have handled all possible actions, and returned a valid state however this is incorrect. My reducer will actually receive other actions such as the INIT action that redux sends when the store is first created. When this reaches my reducer it just returns undefined and now my store is in an unexpected state.

What is the expected behavior?

Obviously I can fix this by just always putting return state at the end of any reducers, but I think that TypeScript should catch this case, createStore should only accept a reducer of the form (state: S | undefined, action: Action) => S

Which versions of Redux, and which browser and OS are affected by this issue? Did this work in previous versions of Redux?

I’m testing with 4.0.4, haven’t tried any other versions.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:18 (10 by maintainers)

github_iconTop GitHub Comments

2reactions
timdorrcommented, Oct 1, 2019

This is because we coerce the INIT and REPLACE actions to your Action type:

https://github.com/reduxjs/redux/blob/25f8a6c92773967d20641c6c239f31c1b01dd459/src/createStore.ts#L340 https://github.com/reduxjs/redux/blob/25f8a6c92773967d20641c6c239f31c1b01dd459/src/createStore.ts#L286

Perhaps we can make something like reducer(state: State, action: ReduxActions<MyActions>) => State that will include the internal actions?

1reaction
jsnajdrcommented, Jan 28, 2020

We ran into a similar (or exactly the same?) issue where the reducer type incorrectly constrains the set of allowed actions.

The Usage with TypeScript guide recommends typing the action parameter as the union of action types the reducer specifically reacts to:

function chatReducer(state = initialState, action: ChatActionTypes): ChatState {
  switch (action.type) {
    case SEND_MESSAGE:
      return ...;
    case DELETE_MESSAGE:
      return ...;
    default:
      return state;
  }
}

But that’s too constraining. A Redux reducer must expect and correctly handle any action of the general-purpose Action type, i.e., an object with a type field.

TypeScript then refuses to compile 100% valid code that calls the reducer:

chatReducer(undefined, { type: 'FOO' });
createStore(chatReducer).dispatch({ type: 'FOO' });

Both these statements fail with:

Type '"FOO"' is not assignable to type '"SEND_MESSAGE" | "DELETE_MESSAGE"'

If I understand the current types correctly, they are great for providing autocomplete hints, but are not that good at the main job of type checking, i.e., checking correctness of the compiled program.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to type Redux actions and Redux reducers in TypeScript?
Strictly speaking, from what I've read, redux runs every single reducer over every possible action. So the action type should literally be any...
Read more >
A Simple Reducer Example with TypeScript, No Need for ...
In this post, we'll cover React Reducers (with the useReducer hook). This tutorial will help you understand: what reducers are.
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. If you are using...
Read more >
Typing a useReducer React hook in TypeScript - Sumo Logic
It is a function that will let us dispatch actions that will trigger state changes. Similarly to ReducerState, ReducerAction extracts action ...
Read more >
Using the useReducer Hook in React with TypeScript
The useReducer hook accepts a reducer type (state, action) ... feature with TypeScript we can create an enum with all of our possible...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found