source: node_modules/@reduxjs/toolkit/src/tests/combineSlices.test-d.ts

Last change on this file was a762898, checked in by istevanoska <ilinastevanoska@…>, 5 months ago

Added visualizations

  • Property mode set to 100644
File size: 7.8 KB
Line 
1import type {
2 Action,
3 Reducer,
4 Slice,
5 WithSlice,
6 WithSlicePreloadedState,
7} from '@reduxjs/toolkit'
8import { combineSlices } from '@reduxjs/toolkit'
9import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
10
11declare const stringSlice: Slice<string, {}, 'string'>
12
13declare const numberSlice: Slice<number, {}, 'number'>
14
15declare const booleanReducer: Reducer<boolean>
16
17declare const mixedReducer: Reducer<string, Action, number>
18
19declare const mixedSliceLike: {
20 reducerPath: 'mixedSlice'
21 reducer: typeof mixedReducer
22}
23
24const exampleApi = createApi({
25 baseQuery: fetchBaseQuery(),
26 endpoints: (build) => ({
27 getThing: build.query({
28 query: () => '',
29 }),
30 }),
31})
32
33type ExampleApiState = ReturnType<typeof exampleApi.reducer>
34
35describe('type tests', () => {
36 test('combineSlices correctly combines static state', () => {
37 const rootReducer = combineSlices(
38 stringSlice,
39 numberSlice,
40 exampleApi,
41 {
42 boolean: booleanReducer,
43 mixed: mixedReducer,
44 },
45 mixedSliceLike,
46 )
47
48 expectTypeOf(rootReducer(undefined, { type: '' })).toEqualTypeOf<{
49 string: string
50 number: number
51 boolean: boolean
52 api: ExampleApiState
53 mixed: string
54 mixedSlice: string
55 }>()
56
57 // test for correct preloaded state handling
58 expectTypeOf(rootReducer).toBeCallableWith(
59 { mixed: 9, mixedSlice: 9 },
60 { type: '' },
61 )
62 })
63
64 test('combineSlices allows passing no initial reducers', () => {
65 const rootReducer = combineSlices()
66
67 expectTypeOf(rootReducer(undefined, { type: '' })).toEqualTypeOf<{}>()
68
69 const declaredLazy =
70 combineSlices().withLazyLoadedSlices<WithSlice<typeof numberSlice>>()
71
72 expectTypeOf(declaredLazy(undefined, { type: '' })).toEqualTypeOf<{
73 number?: number
74 }>()
75 })
76
77 test('withLazyLoadedSlices adds partial to state', () => {
78 const rootReducer = combineSlices(stringSlice).withLazyLoadedSlices<
79 WithSlice<typeof numberSlice> & WithSlice<typeof exampleApi>
80 >()
81
82 expectTypeOf(rootReducer(undefined, { type: '' }).number).toEqualTypeOf<
83 number | undefined
84 >()
85
86 expectTypeOf(rootReducer(undefined, { type: '' }).api).toEqualTypeOf<
87 ExampleApiState | undefined
88 >()
89 })
90
91 test('inject marks injected keys as required', () => {
92 const rootReducer = combineSlices(stringSlice).withLazyLoadedSlices<
93 WithSlice<typeof numberSlice> &
94 WithSlice<typeof exampleApi> & { boolean: boolean } & WithSlice<
95 typeof mixedSliceLike
96 > &
97 WithSlice<{
98 reducerPath: 'mixedReducer'
99 reducer: typeof mixedReducer
100 }>,
101 WithSlicePreloadedState<typeof numberSlice> &
102 WithSlicePreloadedState<typeof exampleApi> & {
103 boolean: boolean
104 } & WithSlicePreloadedState<typeof mixedSliceLike> &
105 WithSlicePreloadedState<{
106 reducerPath: 'mixedReducer'
107 reducer: typeof mixedReducer
108 }>
109 >()
110
111 expectTypeOf(rootReducer(undefined, { type: '' }).number).toEqualTypeOf<
112 number | undefined
113 >()
114
115 expectTypeOf(rootReducer(undefined, { type: '' }).boolean).toEqualTypeOf<
116 boolean | undefined
117 >()
118
119 expectTypeOf(rootReducer(undefined, { type: '' }).api).toEqualTypeOf<
120 ExampleApiState | undefined
121 >()
122
123 expectTypeOf(rootReducer(undefined, { type: '' }).mixedSlice).toEqualTypeOf<
124 string | undefined
125 >()
126
127 expectTypeOf(
128 rootReducer(undefined, { type: '' }).mixedReducer,
129 ).toEqualTypeOf<string | undefined>()
130
131 const withNumber = rootReducer.inject(numberSlice)
132
133 expectTypeOf(withNumber(undefined, { type: '' }).number).toBeNumber()
134
135 const withBool = rootReducer.inject({
136 reducerPath: 'boolean' as const,
137 reducer: booleanReducer,
138 })
139
140 expectTypeOf(withBool(undefined, { type: '' }).boolean).toBeBoolean()
141
142 const withApi = rootReducer.inject(exampleApi)
143
144 expectTypeOf(
145 withApi(undefined, { type: '' }).api,
146 ).toEqualTypeOf<ExampleApiState>()
147
148 const withMixedSlice = rootReducer.inject(mixedSliceLike)
149
150 expectTypeOf(
151 withMixedSlice(undefined, { type: '' }).mixedSlice,
152 ).toBeString()
153
154 const withMixedReducer = rootReducer.inject({
155 reducerPath: 'mixedReducer',
156 reducer: mixedReducer,
157 })
158
159 expectTypeOf(
160 withMixedReducer(undefined, { type: '' }).mixedReducer,
161 ).toBeString()
162 })
163
164 test('selector() allows defining selectors with injected reducers defined', () => {
165 const rootReducer = combineSlices(stringSlice).withLazyLoadedSlices<
166 WithSlice<typeof numberSlice> & { boolean: boolean }
167 >()
168
169 type RootState = ReturnType<typeof rootReducer>
170
171 const withoutInjection = rootReducer.selector(
172 (state: RootState) => state.number,
173 )
174
175 expectTypeOf(
176 withoutInjection(rootReducer(undefined, { type: '' })),
177 ).toEqualTypeOf<number | undefined>()
178
179 const withInjection = rootReducer
180 .inject(numberSlice)
181 .selector((state) => state.number)
182
183 expectTypeOf(
184 withInjection(rootReducer(undefined, { type: '' })),
185 ).toBeNumber()
186 })
187
188 test('selector() passes arguments through', () => {
189 const rootReducer = combineSlices(stringSlice).withLazyLoadedSlices<
190 WithSlice<typeof numberSlice> & { boolean: boolean }
191 >()
192
193 const selector = rootReducer
194 .inject(numberSlice)
195 .selector((state, num: number) => state.number)
196
197 const state = rootReducer(undefined, { type: '' })
198
199 expectTypeOf(selector).toBeCallableWith(state, 0)
200
201 // required argument
202 expectTypeOf(selector).parameters.not.toMatchTypeOf([state])
203
204 // number not string
205 expectTypeOf(selector).parameters.not.toMatchTypeOf([state, ''])
206 })
207
208 test('nested calls inferred correctly', () => {
209 const innerReducer =
210 combineSlices(stringSlice).withLazyLoadedSlices<
211 WithSlice<typeof numberSlice>
212 >()
213
214 const innerSelector = innerReducer.inject(numberSlice).selector(
215 (state) => state.number,
216 (rootState: RootState) => rootState.inner,
217 )
218
219 const outerReducer = combineSlices({ inner: innerReducer })
220
221 type RootState = ReturnType<typeof outerReducer>
222
223 expectTypeOf(outerReducer(undefined, { type: '' })).toMatchTypeOf<{
224 inner: { string: string }
225 }>()
226
227 expectTypeOf(
228 innerSelector(outerReducer(undefined, { type: '' })),
229 ).toBeNumber()
230 })
231
232 test('selector errors if selectorFn and selectState are mismatched', () => {
233 const combinedReducer =
234 combineSlices(stringSlice).withLazyLoadedSlices<
235 WithSlice<typeof numberSlice>
236 >()
237
238 const outerReducer = combineSlices({ inner: combinedReducer })
239
240 type RootState = ReturnType<typeof outerReducer>
241
242 combinedReducer.selector(
243 (state) => state.number,
244 // @ts-expect-error wrong state returned
245 (rootState: RootState) => rootState.inner.number,
246 )
247
248 combinedReducer.selector(
249 (state, num: number) => state.number,
250 // @ts-expect-error wrong arguments
251 (rootState: RootState, str: string) => rootState.inner,
252 )
253
254 combinedReducer.selector(
255 (state, num: number) => state.number,
256 (rootState: RootState) => rootState.inner,
257 )
258
259 // TODO: see if there's a way of making this work
260 // probably a rare case so not the end of the world if not
261 combinedReducer.selector(
262 (state) => state.number,
263 // @ts-ignore
264 (rootState: RootState, num: number) => rootState.inner,
265 )
266 })
267
268 test('correct type of state is inferred when not declared via `withLazyLoadedSlices`', () => {
269 // Related to https://github.com/reduxjs/redux-toolkit/issues/4171
270
271 const combinedReducer = combineSlices(stringSlice)
272
273 const withNumber = combinedReducer.inject(numberSlice)
274
275 expectTypeOf(withNumber).returns.toEqualTypeOf<{
276 string: string
277 number: number
278 }>()
279
280 expectTypeOf(
281 withNumber(undefined, { type: '' }).number,
282 ).toMatchTypeOf<number>()
283 })
284})
Note: See TracBrowser for help on using the repository browser.