Skip to content

Commit 10136fe

Browse files
committed
It passes
1 parent a7428e8 commit 10136fe

File tree

5 files changed

+53
-83
lines changed

5 files changed

+53
-83
lines changed

src/createStore.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import {
55
PreloadedState,
66
StoreEnhancer,
77
Dispatch,
8-
Observer,
9-
ExtendState
8+
Observer
109
} from './types/store'
1110
import { Action } from './types/actions'
1211
import { Reducer } from './types/reducers'
@@ -42,11 +41,11 @@ export default function createStore<
4241
S,
4342
A extends Action,
4443
Ext = {},
45-
StateExt = never
44+
StateExt = {}
4645
>(
4746
reducer: Reducer<S, A>,
4847
enhancer?: StoreEnhancer<Ext, StateExt>
49-
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
48+
): Store<S & StateExt, A, StateExt, Ext> & Ext
5049
export default function createStore<
5150
S,
5251
A extends Action,
@@ -56,7 +55,7 @@ export default function createStore<
5655
reducer: Reducer<S, A>,
5756
preloadedState?: PreloadedState<S>,
5857
enhancer?: StoreEnhancer<Ext, StateExt>
59-
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
58+
): Store<S & StateExt, A, StateExt, Ext> & Ext
6059
export default function createStore<
6160
S,
6261
A extends Action,
@@ -66,7 +65,7 @@ export default function createStore<
6665
reducer: Reducer<S, A>,
6766
preloadedState?: PreloadedState<S> | StoreEnhancer<Ext, StateExt>,
6867
enhancer?: StoreEnhancer<Ext, StateExt>
69-
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext {
68+
): Store<S & StateExt, A, StateExt, Ext> & Ext {
7069
if (
7170
(typeof preloadedState === 'function' && typeof enhancer === 'function') ||
7271
(typeof enhancer === 'function' && typeof arguments[3] === 'function')
@@ -91,7 +90,7 @@ export default function createStore<
9190
return enhancer(createStore)(
9291
reducer,
9392
preloadedState as PreloadedState<S>
94-
) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
93+
) as Store<S & StateExt, A, StateExt, Ext> & Ext
9594
}
9695

9796
if (typeof reducer !== 'function') {
@@ -269,7 +268,7 @@ export default function createStore<
269268
*/
270269
function replaceReducer<NewState, NewActions extends A>(
271270
nextReducer: Reducer<NewState, NewActions>
272-
): Store<ExtendState<NewState, StateExt>, NewActions, StateExt, Ext> & Ext {
271+
): Store<NewState & StateExt, NewActions, StateExt, Ext> & Ext {
273272
if (typeof nextReducer !== 'function') {
274273
throw new Error('Expected the nextReducer to be a function.')
275274
}
@@ -287,7 +286,7 @@ export default function createStore<
287286
dispatch({ type: ActionTypes.REPLACE } as A)
288287
// change the type of the store by casting it to the new store
289288
return (store as unknown) as Store<
290-
ExtendState<NewState, StateExt>,
289+
NewState & StateExt,
291290
NewActions,
292291
StateExt,
293292
Ext
@@ -346,6 +345,6 @@ export default function createStore<
346345
getState,
347346
replaceReducer,
348347
[$$observable]: observable
349-
} as unknown) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
348+
} as unknown) as Store<S & StateExt, A, StateExt, Ext> & Ext
350349
return store
351350
}

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ export {
1919
Store,
2020
StoreCreator,
2121
StoreEnhancer,
22-
StoreEnhancerStoreCreator,
23-
ExtendState
22+
StoreEnhancerStoreCreator
2423
} from './types/store'
2524
// reducers
2625
export {

src/types/store.ts

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,6 @@ import { Action, AnyAction } from './actions'
22
import { Reducer } from './reducers'
33
import '../utils/symbol-observable'
44

5-
/**
6-
* Extend the state
7-
*
8-
* This is used by store enhancers and store creators to extend state.
9-
* If there is no state extension, it just returns the state, as is, otherwise
10-
* it returns the state joined with its extension.
11-
*
12-
* Reference for future devs:
13-
* https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
14-
*/
15-
export type ExtendState<State, Extension> = [Extension] extends [never]
16-
? State
17-
: State & Extension
18-
195
/**
206
* Internal "virtual" symbol used to make the `CombinedState` type unique.
217
*/
@@ -127,7 +113,7 @@ export type Observer<T> = {
127113
export interface Store<
128114
S = any,
129115
A extends Action = AnyAction,
130-
StateExt = never,
116+
StateExt = {},
131117
Ext = {}
132118
> {
133119
/**
@@ -202,7 +188,7 @@ export interface Store<
202188
*/
203189
replaceReducer<NewState, NewActions extends Action>(
204190
nextReducer: Reducer<NewState, NewActions>
205-
): Store<ExtendState<NewState, StateExt>, NewActions, StateExt, Ext> & Ext
191+
): Store<NewState & StateExt, NewActions, StateExt, Ext> & Ext
206192

207193
/**
208194
* Interoperability point for observable/reactive libraries.
@@ -225,15 +211,15 @@ export interface Store<
225211
* @template StateExt State extension that is mixed into the state type.
226212
*/
227213
export interface StoreCreator {
228-
<S, A extends Action, Ext = {}, StateExt = never>(
214+
<S, A extends Action, Ext = {}, StateExt = {}>(
229215
reducer: Reducer<S, A>,
230216
enhancer?: StoreEnhancer<Ext, StateExt>
231-
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
232-
<S, A extends Action, Ext = {}, StateExt = never>(
217+
): Store<S & StateExt, A, StateExt, Ext> & Ext
218+
<S, A extends Action, Ext = {}, StateExt = {}>(
233219
reducer: Reducer<S, A>,
234220
preloadedState?: PreloadedState<S>,
235221
enhancer?: StoreEnhancer<Ext>
236-
): Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
222+
): Store<S & StateExt, A, StateExt, Ext> & Ext
237223
}
238224

239225
/**
@@ -257,13 +243,13 @@ export interface StoreCreator {
257243
* @template Ext Store extension that is mixed into the Store type.
258244
* @template StateExt State extension that is mixed into the state type.
259245
*/
260-
export type StoreEnhancer<Ext = {}, StateExt = never> = <NextExt, NextStateExt>(
246+
export type StoreEnhancer<Ext = {}, StateExt = {}> = <NextExt, NextStateExt>(
261247
next: StoreEnhancerStoreCreator<NextExt, NextStateExt>
262-
) => StoreEnhancerStoreCreator<NextExt & Ext, ExtendState<NextStateExt, StateExt>>
263-
export type StoreEnhancerStoreCreator<Ext = {}, StateExt = never> = <
248+
) => StoreEnhancerStoreCreator<NextExt & Ext, NextStateExt & StateExt>
249+
export type StoreEnhancerStoreCreator<Ext = {}, StateExt = {}> = <
264250
S = any,
265251
A extends Action = AnyAction
266252
>(
267253
reducer: Reducer<S, A>,
268254
preloadedState?: PreloadedState<S>
269-
) => Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
255+
) => Store<S & StateExt, A, StateExt, Ext> & Ext

test/typescript/enhancers.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { StoreEnhancer, Action, AnyAction, Reducer, createStore, StoreEnhancerStoreCreator, Store } from '../..'
2-
import { ExtendState } from '../../src'
32

43
interface State {
54
someField: 'string'
@@ -14,9 +13,9 @@ function dispatchExtension() {
1413

1514
const enhancer: StoreEnhancer<{
1615
dispatch: PromiseDispatch
17-
}> = <NextExt, NextStateExt>(createStore: StoreEnhancerStoreCreator<NextExt, NextStateExt>) => <S, A extends Action = AnyAction>(
18-
reducer: Reducer<S, A>,
19-
preloadedState?: any
16+
}> = createStore => (
17+
reducer,
18+
preloadedState
2019
) => {
2120
const store = createStore(reducer, preloadedState)
2221

@@ -26,7 +25,7 @@ function dispatchExtension() {
2625
store.replaceReducer(nextReducer);
2726
return newStore;
2827
}
29-
28+
3029
const newStore = {
3130
...store,
3231
dispatch: (action: any) => {
@@ -96,11 +95,22 @@ function stateExtension() {
9695
*/
9796
function extraMethods() {
9897
const enhancer: StoreEnhancer<{ method(): string }> = createStore => (
99-
...args
98+
reducer,
99+
preloadedState,
100100
) => {
101-
const store = createStore(...args)
102-
store.method = () => 'foo'
103-
return store
101+
const store = createStore(reducer, preloadedState)
102+
103+
function replaceReducer<NewState, NewActions extends Action>(nextReducer: Reducer<NewState, NewActions>) {
104+
store.replaceReducer(nextReducer)
105+
return newStore
106+
}
107+
108+
const newStore = {
109+
...store,
110+
replaceReducer,
111+
method: () => 'foo'
112+
}
113+
return newStore
104114
}
105115

106116
const store = createStore(reducer, enhancer)
@@ -139,7 +149,19 @@ function replaceReducerExtender() {
139149
extraField: 'extra'
140150
}
141151
: undefined
142-
return createStore(wrappedReducer, wrappedPreloadedState)
152+
153+
function replaceReducer<NewState, NewActions extends Action>(nextReducer: Reducer<NewState, NewActions>) {
154+
store.replaceReducer(nextReducer)
155+
return newStore
156+
}
157+
158+
const store = createStore(wrappedReducer, wrappedPreloadedState)
159+
const newStore = {
160+
...store,
161+
replaceReducer,
162+
method: () => 'foo'
163+
}
164+
return newStore
143165
}
144166

145167
const store = createStore(reducer, enhancer)

test/typescript/store.ts

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import {
55
Action,
66
StoreEnhancer,
77
Unsubscribe,
8-
Observer,
9-
ExtendState
8+
Observer
109
} from '../..'
1110
import 'symbol-observable'
1211

@@ -18,41 +17,6 @@ type State = {
1817
}
1918
}
2019

21-
/* extended state */
22-
const noExtend: ExtendState<State, never> = {
23-
a: 'a',
24-
b: {
25-
c: 'c',
26-
d: 'd'
27-
}
28-
}
29-
// typings:expect-error
30-
const noExtendError: ExtendState<State, never> = {
31-
a: 'a',
32-
b: {
33-
c: 'c',
34-
d: 'd'
35-
},
36-
e: 'oops'
37-
}
38-
39-
const yesExtend: ExtendState<State, { yes: 'we can' }> = {
40-
a: 'a',
41-
b: {
42-
c: 'c',
43-
d: 'd'
44-
},
45-
yes: 'we can'
46-
}
47-
// typings:expect-error
48-
const yesExtendError: ExtendState<State, { yes: 'we can' }> = {
49-
a: 'a',
50-
b: {
51-
c: 'c',
52-
d: 'd'
53-
}
54-
}
55-
5620
interface DerivedAction extends Action {
5721
type: 'a'
5822
b: 'b'

0 commit comments

Comments
 (0)