IleLJzWW3CEAHpVfwjKZjKJ0KxmLlkAAjFBwZAAA3+wMk5r2l26INEYAA-D8-gCuRAAMq6-W5ABC3rA1pofCtzN2nt5AuFRLFpOgQiAA)
<issue_comment>username_2: I have been spending some time thinking through this, and experimenting. Here is what I have found.

1) `this is <blah>` doesn't solve our problem, and I can't figure out why. The documentation of `this-based type guards` is no longer in the official manual for typescript, but there is no announcement anywhere. Also, it still works for XState so <shrug>
2) I don't think this PR takes the correct approach to solving the problem, but I do think it is a real problem. I hope you'll bear with the long explanation below.

Regarding #2, let's examine what the purpose of `replaceReducer` is in Redux. There are 2 use cases I have seen:

1. hot reloading
2. dynamically augmenting the store state

There is another standard method that is more common for augmenting store state in Redux: store enhancers. A store enhancer may extend the state shape or the store shape. The existing code makes strict typing of store enhancers through inference possible, this PR strips out that possibility.

Let's imagine the following scenario:

1. user is using a store enhancer like `ion-router` (https://username_2.github.io/ion-router/) that adds a field to the store shape and augments the store shape. In this case, it adds `router` to the store, and `routing` to the store state. Our store looks like:

```js
{
  router: {...},
  state: {
    routing: {...},
    // user-defined state
  }
  // redux functions
}
```

When the user calls `replaceReducer` to change the reducers to get a new store shape (for instance, to add a lazy-loaded sub-tree of the application that adds new state, say a form widget), the new store shape might be:

```js
{
  router: {...},
  state: {
    routing: {...},
    // previous user-defined state
    // plus the new form widget
    form: {...},
  }
  // redux functions
}
```

This is all perfectly valid javascript. Note that the store enhancer additions to the store shape and to the state shape persist through a `replaceReducer` call.

How do we represent this in typescript? If we don't pass in extra fields to the store interface, this is no longer possible to represent, as `replaceReducer` has no knowledge of the difference between the user-supplied store shape and the store enhancer-provided store shape, and so when it replaces the shape, this is also nuked. Users will have to know all of the store enhancer's shape augmentation and store augmentation to do a correct unsafe type cast.

It also presents a dilemma, which you have stumbled across: how do we tell typescript that the original store variable that `createStore` returned has changed its type?

The current code will preserve the typing and also correctly infer the propagation of the store enhancer chain through `createStore`.

It is true that we will have to use an unsafe cast to continue to use the original store declaration, this change will not propagate automagically throughout the app.

But let's look at how you might make this work.

Let's imagine that you are using the variable `store` and exporting it all over the place, and want to be able to safely type this variable.

You call `store.replaceReducer` with a new reducer.

Now, you will need to scatter `(store as unknown as Store<NewState, NewA>)` all over the app. This gets tedious, so you might find yourself doing:

```ts
store.replaceReducer(newReducer);
const newStore = (store as unknown as Store<NewState, NewA>);
```

and then using `newStore` instead. This is slightly longer than:

```ts
const newStore = store.replaceReducer(newReducer);
```

and requires using a very unsafe double type cast. In the end, this is unlikely to be a good solution, because how do we know for certain which version of the store shape is in use?

The answer I see is a different approach: using type guards at the point the store is used.

If you have code that relies upon strict typing to differentiate between two different possible store shapes, you should write 2 type guards:

```ts
function isStore1<S extends Store>(store: S): store is S & StoreShape1 {
  return store.getState().shape1!== undefined
[Truncated]
}
```

then, you can use this in the code:

```ts
if (isStore1(store)) {
  // operate on store with shape 1
} else if (isStore2(store)) {
  // operate on store with shape 2
}
```

In other words, I don't think redux is the correct surface to fix the problem you are encountering. It is definitely a problem, but there is no generic way to solve your specific issue. However, the code that is in redux that this PR strips **does** solve the problem of store enhancers that augment the store or state shape in a generic, chainable fashion so that you can use createStore with any store enhancer and still use `replaceReducer` with strict type safety.

For these reasons, I don't think this PR is the right solution. I think the right solution is perhaps to add something similar to the explanation above to the documentation.

Thanks for being patient, I have zero time to do proper investigations during the week right now with working from home and full-time parenting. Also, thanks for raising this issue and putting so much effort in, I am definitely interested in having further dialog with you, @username_1 and @markerikson about these points.

I think it's fair to say all of this is pretty edge case-y for most folks who use redux (we don't use any of this fanciness in my workplace, for instance. The most avant garde stuff we use is thunks, and even that is about to be stripped out in favor of using redux only as the caching layer), so it may be that we 2 are the only people who care about this. Either way, let's see if we can come to a resolution that works for your needs.
<issue_comment>username_0: @username_2 Thanks for spending the time to think about this some more, I really appreciate it. I'm working on TypeScript-ing `redux-devtools` right now, hence the onslaught of issues/PRs regarding the types for enhancers/stores. We might very well be the only two people who care about this.

The example you provided is very helpful and helps ground the discussion. I agree that having some type-safety is the whole point of using TypeScript, and so if we lower ability for the types to catch mistakes, then it's not serving its purpose (that's why we have `dispatch()` accept a user-specified generic action, even though it should be able to accept any action in reality).

I'm gonna dig into it a little bit more and see what I can come up with. Again, really appreciate the response.
<issue_comment>username_0: reducer: Reducer<S, A>,
  preloadedState?: any
) => {
  const wrapReducer = (reducer: Reducer<S, A>): Reducer<S & ExtraState, A> => (
    state,
    action
  ) => {
    const newState = reducer(state, action);
    return {
     ...newState,
      extraField: "extra",
    };
  };
  const wrappedPreloadedState = preloadedState
   ? {
       ...preloadedState,
        extraField: "extra",
      }
    : undefined;

  const store = createStore(wrapReducer(reducer), wrappedPreloadedState);
  return {
   ...store,
    replaceReducer(nextReducer: Reducer<S, A>) {
      // I forgot to re-wrap the reducer and got this error:
      // TS2345: Argument of type 'Reducer<S, A>' is not assignable to parameter of type 'Reducer<S & ExtraState, A>'.
      //   Type 'S' is not assignable to type 'S & ExtraState'.
      //     Type 'S' is not assignable to type 'ExtraState'.
      store.replaceReducer(nextReducer);
    },
  };
};
```

I think those are the main bugs that an enhancer author can make. Sorry for the long code samples. Let me