Skip to content

Commit 793c5d5

Browse files
authored
Merge pull request #2001 from reduxjs/feature/gdm-array-types
2 parents f86d1e6 + 3ff7137 commit 793c5d5

File tree

9 files changed

+245
-116
lines changed

9 files changed

+245
-116
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ jobs:
9696
fail-fast: false
9797
matrix:
9898
node: ['14.x']
99-
ts: ['3.9', '4.0', '4.1', '4.2', '4.3', '4.4', '4.5', 'next']
99+
ts: ['4.1', '4.2', '4.3', '4.4', '4.5', 'next']
100100
steps:
101101
- name: Checkout repo
102102
uses: actions/checkout@v2

packages/action-listener-middleware/src/tests/fork.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ describe('fork', () => {
5252
},
5353
})
5454
const { increment, decrement, incrementByAmount } = counterSlice.actions
55-
let middleware: ReturnType<typeof createActionListenerMiddleware>
56-
let store: EnhancedStore<CounterSlice>
55+
let middleware = createActionListenerMiddleware()
56+
let store = configureStore({
57+
reducer: counterSlice.reducer,
58+
middleware: (gDM) => gDM().prepend(middleware),
59+
})
5760

5861
beforeEach(() => {
5962
middleware = createActionListenerMiddleware()

packages/toolkit/src/configureStore.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import type {
2020
CurriedGetDefaultMiddleware,
2121
} from './getDefaultMiddleware'
2222
import { curryGetDefaultMiddleware } from './getDefaultMiddleware'
23-
import type { DispatchForMiddlewares, NoInfer } from './tsHelpers'
23+
import type { NoInfer, ExtractDispatchExtensions } from './tsHelpers'
2424

2525
const IS_PRODUCTION = process.env.NODE_ENV === 'production'
2626

@@ -110,7 +110,7 @@ export interface EnhancedStore<
110110
*
111111
* @inheritdoc
112112
*/
113-
dispatch: Dispatch<A> & DispatchForMiddlewares<M>
113+
dispatch: ExtractDispatchExtensions<M> & Dispatch<A>
114114
}
115115

116116
/**
@@ -160,7 +160,7 @@ export function configureStore<
160160
}
161161
if (
162162
!IS_PRODUCTION &&
163-
finalMiddleware.some((item) => typeof item !== 'function')
163+
finalMiddleware.some((item: any) => typeof item !== 'function')
164164
) {
165165
throw new Error(
166166
'each middleware provided to configureStore must be a function'

packages/toolkit/src/getDefaultMiddleware.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { createImmutableStateInvariantMiddleware } from './immutableStateInvaria
88

99
import type { SerializableStateInvariantMiddlewareOptions } from './serializableStateInvariantMiddleware'
1010
import { createSerializableStateInvariantMiddleware } from './serializableStateInvariantMiddleware'
11+
import type { ExcludeFromTuple } from './tsHelpers'
1112
import { MiddlewareArray } from './utils'
1213

1314
function isBoolean(x: any): x is boolean {
@@ -33,9 +34,7 @@ export type ThunkMiddlewareFor<
3334
? never
3435
: O extends { thunk: { extraArgument: infer E } }
3536
? ThunkMiddleware<S, AnyAction, E>
36-
:
37-
| ThunkMiddleware<S, AnyAction, null> //The ThunkMiddleware with a `null` ExtraArgument is here to provide backwards-compatibility.
38-
| ThunkMiddleware<S, AnyAction>
37+
: ThunkMiddleware<S, AnyAction>
3938

4039
export type CurriedGetDefaultMiddleware<S = any> = <
4140
O extends Partial<GetDefaultMiddlewareOptions> = {
@@ -45,7 +44,7 @@ export type CurriedGetDefaultMiddleware<S = any> = <
4544
}
4645
>(
4746
options?: O
48-
) => MiddlewareArray<Middleware<{}, S> | ThunkMiddlewareFor<S, O>>
47+
) => MiddlewareArray<ExcludeFromTuple<[ThunkMiddlewareFor<S, O>], never>>
4948

5049
export function curryGetDefaultMiddleware<
5150
S = any
@@ -76,14 +75,14 @@ export function getDefaultMiddleware<
7675
}
7776
>(
7877
options: O = {} as O
79-
): MiddlewareArray<Middleware<{}, S> | ThunkMiddlewareFor<S, O>> {
78+
): MiddlewareArray<ExcludeFromTuple<[ThunkMiddlewareFor<S, O>], never>> {
8079
const {
8180
thunk = true,
8281
immutableCheck = true,
8382
serializableCheck = true,
8483
} = options
8584

86-
let middlewareArray: Middleware<{}, S>[] = new MiddlewareArray()
85+
let middlewareArray = new MiddlewareArray<Middleware[]>()
8786

8887
if (thunk) {
8988
if (isBoolean(thunk)) {
Lines changed: 62 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { getDefaultMiddleware } from '@reduxjs/toolkit'
1+
import { getDefaultMiddleware, configureStore } from '@reduxjs/toolkit'
22
import type { Middleware } from 'redux'
3-
import type { DispatchForMiddlewares } from '@internal/tsHelpers'
43

54
declare const expectType: <T>(t: T) => T
65

@@ -12,103 +11,108 @@ declare const middleware2: Middleware<{
1211
(_: number): string
1312
}>
1413

15-
declare const getDispatch: <M extends Array<Middleware>>(
16-
m: M
17-
) => DispatchForMiddlewares<M>
18-
1914
type ThunkReturn = Promise<'thunk'>
2015
declare const thunkCreator: () => () => ThunkReturn
2116

2217
{
23-
const defaultMiddleware = getDefaultMiddleware()
24-
2518
// prepend single element
2619
{
27-
const concatenated = defaultMiddleware.prepend(middleware1)
28-
const dispatch = getDispatch(concatenated)
29-
expectType<number>(dispatch('foo'))
30-
expectType<ThunkReturn>(dispatch(thunkCreator()))
20+
const store = configureStore({
21+
reducer: () => 0,
22+
middleware: (gDM) => gDM().prepend(middleware1),
23+
})
24+
expectType<number>(store.dispatch('foo'))
25+
expectType<ThunkReturn>(store.dispatch(thunkCreator()))
3126

3227
// @ts-expect-error
33-
expectType<string>(dispatch('foo'))
28+
expectType<string>(store.dispatch('foo'))
3429
}
3530

36-
// prepepend multiple (rest)
31+
// prepend multiple (rest)
3732
{
38-
const concatenated = defaultMiddleware.prepend(middleware1, middleware2)
39-
const dispatch = getDispatch(concatenated)
40-
expectType<number>(dispatch('foo'))
41-
expectType<string>(dispatch(5))
42-
expectType<ThunkReturn>(dispatch(thunkCreator()))
33+
const store = configureStore({
34+
reducer: () => 0,
35+
middleware: (gDM) => gDM().prepend(middleware1, middleware2),
36+
})
37+
expectType<number>(store.dispatch('foo'))
38+
expectType<string>(store.dispatch(5))
39+
expectType<ThunkReturn>(store.dispatch(thunkCreator()))
4340

4441
// @ts-expect-error
45-
expectType<string>(dispatch('foo'))
42+
expectType<string>(store.dispatch('foo'))
4643
}
4744

4845
// prepend multiple (array notation)
4946
{
50-
const concatenated = defaultMiddleware.prepend([
51-
middleware1,
52-
middleware2,
53-
] as const)
54-
const dispatch = getDispatch(concatenated)
55-
expectType<number>(dispatch('foo'))
56-
expectType<string>(dispatch(5))
57-
expectType<ThunkReturn>(dispatch(thunkCreator()))
47+
const store = configureStore({
48+
reducer: () => 0,
49+
middleware: (gDM) => gDM().prepend([middleware1, middleware2] as const),
50+
})
51+
52+
expectType<number>(store.dispatch('foo'))
53+
expectType<string>(store.dispatch(5))
54+
expectType<ThunkReturn>(store.dispatch(thunkCreator()))
5855

5956
// @ts-expect-error
60-
expectType<string>(dispatch('foo'))
57+
expectType<string>(store.dispatch('foo'))
6158
}
6259

6360
// concat single element
6461
{
65-
const concatenated = defaultMiddleware.concat(middleware1)
66-
const dispatch = getDispatch(concatenated)
67-
expectType<number>(dispatch('foo'))
68-
expectType<ThunkReturn>(dispatch(thunkCreator()))
62+
const store = configureStore({
63+
reducer: () => 0,
64+
middleware: (gDM) => gDM().concat(middleware1),
65+
})
66+
67+
expectType<number>(store.dispatch('foo'))
68+
expectType<ThunkReturn>(store.dispatch(thunkCreator()))
6969

7070
// @ts-expect-error
71-
expectType<string>(dispatch('foo'))
71+
expectType<string>(store.dispatch('foo'))
7272
}
7373

74-
// prepepend multiple (rest)
74+
// prepend multiple (rest)
7575
{
76-
const concatenated = defaultMiddleware.concat(middleware1, middleware2)
77-
const dispatch = getDispatch(concatenated)
78-
expectType<number>(dispatch('foo'))
79-
expectType<string>(dispatch(5))
80-
expectType<ThunkReturn>(dispatch(thunkCreator()))
76+
const store = configureStore({
77+
reducer: () => 0,
78+
middleware: (gDM) => gDM().concat(middleware1, middleware2),
79+
})
80+
81+
expectType<number>(store.dispatch('foo'))
82+
expectType<string>(store.dispatch(5))
83+
expectType<ThunkReturn>(store.dispatch(thunkCreator()))
8184

8285
// @ts-expect-error
83-
expectType<string>(dispatch('foo'))
86+
expectType<string>(store.dispatch('foo'))
8487
}
8588

8689
// concat multiple (array notation)
8790
{
88-
const concatenated = defaultMiddleware.concat([
89-
middleware1,
90-
middleware2,
91-
] as const)
92-
const dispatch = getDispatch(concatenated)
93-
expectType<number>(dispatch('foo'))
94-
expectType<string>(dispatch(5))
95-
expectType<ThunkReturn>(dispatch(thunkCreator()))
91+
const store = configureStore({
92+
reducer: () => 0,
93+
middleware: (gDM) => gDM().concat([middleware1, middleware2] as const),
94+
})
95+
96+
expectType<number>(store.dispatch('foo'))
97+
expectType<string>(store.dispatch(5))
98+
expectType<ThunkReturn>(store.dispatch(thunkCreator()))
9699

97100
// @ts-expect-error
98-
expectType<string>(dispatch('foo'))
101+
expectType<string>(store.dispatch('foo'))
99102
}
100103

101104
// concat and prepend
102105
{
103-
const concatenated = defaultMiddleware
104-
.concat(middleware1)
105-
.prepend(middleware2)
106-
const dispatch = getDispatch(concatenated)
107-
expectType<number>(dispatch('foo'))
108-
expectType<string>(dispatch(5))
109-
expectType<ThunkReturn>(dispatch(thunkCreator()))
106+
const store = configureStore({
107+
reducer: () => 0,
108+
middleware: (gDM) => gDM().concat(middleware1).prepend(middleware2),
109+
})
110+
111+
expectType<number>(store.dispatch('foo'))
112+
expectType<string>(store.dispatch(5))
113+
expectType<ThunkReturn>(store.dispatch(thunkCreator()))
110114

111115
// @ts-expect-error
112-
expectType<string>(dispatch('foo'))
116+
expectType<string>(store.dispatch('foo'))
113117
}
114118
}

0 commit comments

Comments
 (0)