Skip to content

Commit

Permalink
Revert adding the store as a return type to replaceReducer
Browse files Browse the repository at this point in the history
  • Loading branch information
Methuselah96 committed Jan 28, 2023
1 parent 5193835 commit 1f12c51
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 130 deletions.
35 changes: 11 additions & 24 deletions src/createStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {
PreloadedState,
StoreEnhancer,
Dispatch,
Observer,
ExtendState
Observer
} from './types/store'
import { Action } from './types/actions'
import { Reducer } from './types/reducers'
Expand Down Expand Up @@ -42,7 +41,7 @@ import { kindOf } from './utils/kindOf'
export function createStore<S, A extends Action, Ext = {}, StateExt = never>(
reducer: Reducer<S, A>,
enhancer?: StoreEnhancer<Ext, StateExt>
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
): Store<S, A, StateExt> & Ext
/**
* @deprecated
*
Expand Down Expand Up @@ -72,12 +71,12 @@ export function createStore<S, A extends Action, Ext = {}, StateExt = never>(
reducer: Reducer<S, A>,
preloadedState?: PreloadedState<S>,
enhancer?: StoreEnhancer<Ext, StateExt>
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
): Store<S, A, StateExt> & Ext
export function createStore<S, A extends Action, Ext = {}, StateExt = never>(
reducer: Reducer<S, A>,
preloadedState?: PreloadedState<S> | StoreEnhancer<Ext, StateExt>,
enhancer?: StoreEnhancer<Ext, StateExt>
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext {
): Store<S, A, StateExt> & Ext {
if (typeof reducer !== 'function') {
throw new Error(
`Expected the root reducer to be a function. Instead, received: '${kindOf(
Expand Down Expand Up @@ -114,7 +113,7 @@ export function createStore<S, A extends Action, Ext = {}, StateExt = never>(
return enhancer(createStore)(
reducer,
preloadedState as PreloadedState<S>
) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
) as Store<S, A, StateExt> & Ext
}

let currentReducer = reducer
Expand Down Expand Up @@ -288,11 +287,8 @@ export function createStore<S, A extends Action, Ext = {}, StateExt = never>(
* implement a hot reloading mechanism for Redux.
*
* @param nextReducer The reducer for the store to use instead.
* @returns The same store instance with a new reducer in place.
*/
function replaceReducer<NewState, NewActions extends A>(
nextReducer: Reducer<NewState, NewActions>
): Store<ExtendState<NewState, StateExt>, NewActions, StateExt, Ext> & Ext {
function replaceReducer(nextReducer: Reducer<S, A>): void {
if (typeof nextReducer !== 'function') {
throw new Error(
`Expected the nextReducer to be a function. Instead, received: '${kindOf(
Expand All @@ -301,22 +297,13 @@ export function createStore<S, A extends Action, Ext = {}, StateExt = never>(
)
}

// TODO: do this more elegantly
;(currentReducer as unknown as Reducer<NewState, NewActions>) = nextReducer
currentReducer = nextReducer

// This action has a similar effect to ActionTypes.INIT.
// Any reducers that existed in both the new and old rootReducer
// will receive the previous state. This effectively populates
// the new state tree with any relevant data from the old one.
dispatch({ type: ActionTypes.REPLACE } as A)
// change the type of the store by casting it to the new store
return store as unknown as Store<
ExtendState<NewState, StateExt>,
NewActions,
StateExt,
Ext
> &
Ext
}

/**
Expand Down Expand Up @@ -374,7 +361,7 @@ export function createStore<S, A extends Action, Ext = {}, StateExt = never>(
getState,
replaceReducer,
[$$observable]: observable
} as unknown as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
} as unknown as Store<S, A, StateExt> & Ext
return store
}

Expand Down Expand Up @@ -416,7 +403,7 @@ export function legacy_createStore<
>(
reducer: Reducer<S, A>,
enhancer?: StoreEnhancer<Ext, StateExt>
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
): Store<S, A, StateExt> & Ext
/**
* Creates a Redux store that holds the state tree.
*
Expand Down Expand Up @@ -456,7 +443,7 @@ export function legacy_createStore<
reducer: Reducer<S, A>,
preloadedState?: PreloadedState<S>,
enhancer?: StoreEnhancer<Ext, StateExt>
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
): Store<S, A, StateExt> & Ext
export function legacy_createStore<
S,
A extends Action,
Expand All @@ -466,6 +453,6 @@ export function legacy_createStore<
reducer: Reducer<S, A>,
preloadedState?: PreloadedState<S> | StoreEnhancer<Ext, StateExt>,
enhancer?: StoreEnhancer<Ext, StateExt>
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext {
): Store<S, A, StateExt> & Ext {
return createStore(reducer, preloadedState as any, enhancer)
}
18 changes: 7 additions & 11 deletions src/types/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,11 @@ export type Observer<T> = {
* @template S The type of state held by this store.
* @template A the type of actions which may be dispatched by this store.
* @template StateExt any extension to state from store enhancers
* @template Ext any extensions to the store from store enhancers
*/
export interface Store<
S = any,
A extends Action = AnyAction,
StateExt = never,
Ext = {}
StateExt = never
> {
/**
* Dispatches an action. It is the only way to trigger a state change.
Expand Down Expand Up @@ -172,7 +170,7 @@ export interface Store<
*
* @returns The current state tree of your application.
*/
getState(): S
getState(): ExtendState<S, StateExt>

/**
* Adds a change listener. It will be called any time an action is
Expand Down Expand Up @@ -209,17 +207,15 @@ export interface Store<
*
* @param nextReducer The reducer for the store to use instead.
*/
replaceReducer<NewState, NewActions extends Action>(
nextReducer: Reducer<NewState, NewActions>
): Store<ExtendState<NewState, StateExt>, NewActions, StateExt, Ext> & Ext
replaceReducer(nextReducer: Reducer<S, A>): void

/**
* Interoperability point for observable/reactive libraries.
* @returns {observable} A minimal observable of state changes.
* For more information, see the observable proposal:
* https://github.com/tc39/proposal-observable
*/
[Symbol.observable](): Observable<S>
[Symbol.observable](): Observable<ExtendState<S, StateExt>>
}

/**
Expand All @@ -237,12 +233,12 @@ export interface StoreCreator {
<S, A extends Action, Ext = {}, StateExt = never>(
reducer: Reducer<S, A>,
enhancer?: StoreEnhancer<Ext, StateExt>
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
): Store<S, A, StateExt> & Ext
<S, A extends Action, Ext = {}, StateExt = never>(
reducer: Reducer<S, A>,
preloadedState?: PreloadedState<S>,
enhancer?: StoreEnhancer<Ext>
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
): Store<S, A, StateExt> & Ext
}

/**
Expand Down Expand Up @@ -275,4 +271,4 @@ export type StoreEnhancerStoreCreator<Ext = {}, StateExt = never> = <
>(
reducer: Reducer<S, A>,
preloadedState?: PreloadedState<S>
) => Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
) => Store<S, A, StateExt> & Ext
25 changes: 16 additions & 9 deletions test/combineReducers.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/* eslint-disable no-console */
import {
createStore,
combineReducers,
Reducer,
__DO_NOT_USE__ActionTypes as ActionTypes,
Action,
AnyAction,
__DO_NOT_USE__ActionTypes as ActionTypes
combineReducers,
createStore,
Reducer
} from '..'

describe('Utils', () => {
Expand Down Expand Up @@ -327,31 +328,35 @@ describe('Utils', () => {
const ACTION = { type: 'ACTION' }

it('should return an updated state when additional reducers are passed to combineReducers', function () {
const originalCompositeReducer = combineReducers({ foo })
type State = { foo: {}; bar?: {} }

const originalCompositeReducer = combineReducers<State>({ foo })
const store = createStore(originalCompositeReducer)

store.dispatch(ACTION)

const initialState = store.getState()

store.replaceReducer(combineReducers({ foo, bar }))
store.replaceReducer(combineReducers<State>({ foo, bar }))
store.dispatch(ACTION)

const nextState = store.getState()
expect(nextState).not.toBe(initialState)
})

it('should return an updated state when reducers passed to combineReducers are changed', function () {
type State = { foo?: {}; bar: {}; baz?: {} }

const baz = (state = {}) => state

const originalCompositeReducer = combineReducers({ foo, bar })
const originalCompositeReducer = combineReducers<State>({ foo, bar })
const store = createStore(originalCompositeReducer)

store.dispatch(ACTION)

const initialState = store.getState()

store.replaceReducer(combineReducers({ baz, bar }))
store.replaceReducer(combineReducers<State>({ baz, bar }))
store.dispatch(ACTION)

const nextState = store.getState()
Expand All @@ -374,7 +379,9 @@ describe('Utils', () => {
})

it('should return an updated state when one of more reducers passed to the combineReducers are removed', function () {
const originalCompositeReducer = combineReducers({ foo, bar })
const originalCompositeReducer = combineReducers<{ foo?: {}; bar: {} }>(
{ foo, bar }
)
const store = createStore(originalCompositeReducer)

store.dispatch(ACTION)
Expand Down
15 changes: 5 additions & 10 deletions test/createStore.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -823,22 +823,17 @@ describe('createStore', () => {
const originalConsoleError = console.error
console.error = jest.fn()

type State = { x?: number; y: { z: number; w?: number } }

const store = createStore(
combineReducers({
combineReducers<State>({
x: (s = 0, _) => s,
y: combineReducers({
z: (s = 0, _) => s,
w: (s = 0, _) => s
})
y: combineReducers({ z: (s = 0, _) => s, w: (s = 0, _) => s })
})
)

store.replaceReducer(
combineReducers({
y: combineReducers({
z: (s = 0, _) => s
})
})
combineReducers({ y: combineReducers({ z: (s = 0, _) => s }) })
)

expect((console.error as any).mock.calls.length).toBe(0)
Expand Down
18 changes: 0 additions & 18 deletions test/replaceReducers.spec.ts

This file was deleted.

Loading

0 comments on commit 1f12c51

Please sign in to comment.