Skip to content

Commit 37ab272

Browse files
author
ben.durrant
committed
add reducerPath option to slice
1 parent ef07e12 commit 37ab272

File tree

5 files changed

+90
-148
lines changed

5 files changed

+90
-148
lines changed

packages/toolkit/src/combineSlices.ts

Lines changed: 43 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -14,68 +14,37 @@ import type {
1414
WithOptionalProp,
1515
} from './tsHelpers'
1616

17-
type SliceLike<Name extends string, State> = {
18-
name: Name
19-
reducer: Reducer<State>
20-
}
21-
22-
type AnySliceLike = SliceLike<string, any>
23-
24-
type SliceLikeState<Sl extends AnySliceLike> = Sl extends SliceLike<
25-
any,
26-
infer State
27-
>
28-
? State
29-
: never
30-
31-
type SliceLikeName<Sl extends AnySliceLike> = Sl extends SliceLike<
32-
infer Name,
33-
any
34-
>
35-
? Name
36-
: never
37-
38-
export type WithSlice<Sl extends AnySliceLike> = Id<
39-
{
40-
[K in SliceLikeName<Sl>]: SliceLikeState<Sl>
41-
}
42-
>
43-
44-
type ApiLike<ReducerPath extends string, State> = {
17+
type SliceLike<ReducerPath extends string, State> = {
4518
reducerPath: ReducerPath
4619
reducer: Reducer<State>
4720
}
4821

49-
type AnyApiLike = ApiLike<string, any>
22+
type AnySliceLike = SliceLike<string, any>
5023

51-
type ApiLikeReducerPath<A extends AnyApiLike> = A extends ApiLike<
24+
type SliceLikeReducerPath<A extends AnySliceLike> = A extends SliceLike<
5225
infer ReducerPath,
5326
any
5427
>
5528
? ReducerPath
5629
: never
5730

58-
type ApiLikeState<A extends AnyApiLike> = A extends ApiLike<any, infer State>
31+
type SliceLikeState<A extends AnySliceLike> = A extends SliceLike<
32+
any,
33+
infer State
34+
>
5935
? State
6036
: never
6137

62-
export type WithApi<A extends AnyApiLike> = {
63-
[Path in ApiLikeReducerPath<A>]: ApiLikeState<A>
38+
export type WithSlice<A extends AnySliceLike> = {
39+
[Path in SliceLikeReducerPath<A>]: SliceLikeState<A>
6440
}
6541

6642
type ReducerMap = Record<string, Reducer>
6743

6844
type ExistingSliceLike<DeclaredState> = {
69-
[Name in keyof DeclaredState]: SliceLike<
70-
Name & string,
71-
NonUndefined<DeclaredState[Name]>
72-
>
73-
}[keyof DeclaredState]
74-
75-
type ExistingApiLike<DeclaredState> = {
76-
[Name in keyof DeclaredState]: ApiLike<
77-
Name & string,
78-
NonUndefined<DeclaredState[Name]>
45+
[ReducerPath in keyof DeclaredState]: SliceLike<
46+
ReducerPath & string,
47+
NonUndefined<DeclaredState[ReducerPath]>
7948
>
8049
}[keyof DeclaredState]
8150

@@ -123,58 +92,23 @@ export interface CombinedSliceReducer<
12392
* }
12493
* }
12594
*
126-
* const withCustom = rootReducer.inject({ name: "customName", reducer: customSlice.reducer })
95+
* const withCustom = rootReducer.inject({ reducerPath: "customName", reducer: customSlice.reducer })
12796
* ```
12897
*/
12998
withLazyLoadedSlices<Lazy = {}>(): CombinedSliceReducer<
13099
InitialState,
131100
Id<DeclaredState & Partial<Lazy>>
132101
>
133102

134-
/**
135-
* Inject an RTKQ API instance.
136-
*
137-
* Accepts an individual instance, or an "api-like" { reducerPath, reducer } object
138-
*
139-
* ```ts
140-
* rootReducer.inject(baseApi)
141-
* ```
142-
*
143-
*/
144-
inject<A extends ExistingApiLike<DeclaredState>>(
145-
api: A,
146-
config?: InjectConfig
147-
): CombinedSliceReducer<InitialState, Id<DeclaredState & WithApi<A>>>
148-
149-
/**
150-
* Inject an RTKQ API instance.
151-
*
152-
* Accepts an individual instance, or an "api-like" { reducerPath, reducer } object
153-
*
154-
* ```ts
155-
* rootReducer.inject(baseApi)
156-
* ```
157-
*
158-
*/
159-
inject<ReducerPath extends string, State>(
160-
api: ApiLike<
161-
ReducerPath,
162-
State & (ReducerPath extends keyof DeclaredState ? never : State)
163-
>,
164-
config?: InjectConfig
165-
): CombinedSliceReducer<
166-
InitialState,
167-
Id<DeclaredState & WithApi<ApiLike<ReducerPath, State>>>
168-
>
169-
170103
/**
171104
* Inject a slice.
172105
*
173-
* Accepts an individual slice, or a "slice-like" { name, reducer } object.
106+
* Accepts an individual slice, RTKQ API instance, or a "slice-like" { reducerPath, reducer } object.
174107
*
175108
* ```ts
176109
* rootReducer.inject(booleanSlice)
177-
* rootReducer.inject({ name: 'boolean' as const, reducer: newReducer }, { overrideExisting: true })
110+
* rootReducer.inject(baseApi)
111+
* rootReducer.inject({ reducerPath: 'boolean' as const, reducer: newReducer }, { overrideExisting: true })
178112
* ```
179113
*
180114
*/
@@ -186,23 +120,24 @@ export interface CombinedSliceReducer<
186120
/**
187121
* Inject a slice.
188122
*
189-
* Accepts an individual slice, or a "slice-like" { name, reducer } object.
123+
* Accepts an individual slice, RTKQ API instance, or a "slice-like" { reducerPath, reducer } object.
190124
*
191125
* ```ts
192126
* rootReducer.inject(booleanSlice)
193-
* rootReducer.inject({ name: 'boolean' as const, reducer: newReducer }, { overrideExisting: true })
127+
* rootReducer.inject(baseApi)
128+
* rootReducer.inject({ reducerPath: 'boolean' as const, reducer: newReducer }, { overrideExisting: true })
194129
* ```
195130
*
196131
*/
197-
inject<Name extends string, State>(
132+
inject<ReducerPath extends string, State>(
198133
slice: SliceLike<
199-
Name,
200-
State & (Name extends keyof DeclaredState ? never : State)
134+
ReducerPath,
135+
State & (ReducerPath extends keyof DeclaredState ? never : State)
201136
>,
202137
config?: InjectConfig
203138
): CombinedSliceReducer<
204139
InitialState,
205-
Id<DeclaredState & WithSlice<SliceLike<Name, String>>>
140+
Id<DeclaredState & WithSlice<SliceLike<ReducerPath, String>>>
206141
>
207142

208143
/**
@@ -373,33 +308,24 @@ export interface CombinedSliceReducer<
373308
}
374309
}
375310

376-
type InitialState<
377-
Slices extends Array<AnySliceLike | AnyApiLike | ReducerMap>
378-
> = UnionToIntersection<
379-
Slices[number] extends infer Slice
380-
? Slice extends AnySliceLike
381-
? WithSlice<Slice>
382-
: Slice extends AnyApiLike
383-
? WithApi<Slice>
384-
: StateFromReducersMapObject<Slice>
385-
: never
386-
>
311+
type InitialState<Slices extends Array<AnySliceLike | ReducerMap>> =
312+
UnionToIntersection<
313+
Slices[number] extends infer Slice
314+
? Slice extends AnySliceLike
315+
? WithSlice<Slice>
316+
: StateFromReducersMapObject<Slice>
317+
: never
318+
>
387319

388320
const isSliceLike = (
389-
maybeSliceLike: AnySliceLike | AnyApiLike | ReducerMap
321+
maybeSliceLike: AnySliceLike | ReducerMap
390322
): maybeSliceLike is AnySliceLike =>
391-
'name' in maybeSliceLike && typeof maybeSliceLike.name === 'string'
323+
'reducerPath' in maybeSliceLike &&
324+
typeof maybeSliceLike.reducerPath === 'string'
392325

393-
const isApiLike = (
394-
maybeApiLike: AnySliceLike | AnyApiLike | ReducerMap
395-
): maybeApiLike is AnyApiLike =>
396-
'reducerPath' in maybeApiLike && typeof maybeApiLike.reducerPath === 'string'
397-
398-
const getReducers = (slices: Array<AnySliceLike | AnyApiLike | ReducerMap>) =>
326+
const getReducers = (slices: Array<AnySliceLike | ReducerMap>) =>
399327
slices.flatMap((sliceOrMap) =>
400328
isSliceLike(sliceOrMap)
401-
? [[sliceOrMap.name, sliceOrMap.reducer] as const]
402-
: isApiLike(sliceOrMap)
403329
? [[sliceOrMap.reducerPath, sliceOrMap.reducer] as const]
404330
: Object.entries(sliceOrMap)
405331
)
@@ -452,9 +378,9 @@ const original = (state: any) => {
452378
return state[ORIGINAL_STATE]
453379
}
454380

455-
export function combineSlices<
456-
Slices extends Array<AnySliceLike | AnyApiLike | ReducerMap>
457-
>(...slices: Slices): CombinedSliceReducer<Id<InitialState<Slices>>> {
381+
export function combineSlices<Slices extends Array<AnySliceLike | ReducerMap>>(
382+
...slices: Slices
383+
): CombinedSliceReducer<Id<InitialState<Slices>>> {
458384
const reducerMap = Object.fromEntries<Reducer>(getReducers(slices))
459385

460386
const getReducer = () => combineReducers(reducerMap)
@@ -468,22 +394,12 @@ export function combineSlices<
468394
combinedReducer.withLazyLoadedSlices = () => combinedReducer
469395

470396
const inject = (
471-
slice: AnySliceLike | AnyApiLike,
397+
slice: AnySliceLike,
472398
config: InjectConfig = {}
473399
): typeof combinedReducer => {
474-
if (isApiLike(slice)) {
475-
return inject(
476-
{
477-
name: slice.reducerPath,
478-
reducer: slice.reducer,
479-
},
480-
config
481-
)
482-
}
483-
484-
const { name, reducer: reducerToInject } = slice
400+
const { reducerPath, reducer: reducerToInject } = slice
485401

486-
const currentReducer = reducerMap[name]
402+
const currentReducer = reducerMap[reducerPath]
487403
if (
488404
!config.overrideExisting &&
489405
currentReducer &&
@@ -494,14 +410,14 @@ export function combineSlices<
494410
process.env.NODE_ENV === 'development'
495411
) {
496412
console.error(
497-
`called \`inject\` to override already-existing reducer ${name} without specifying \`overrideExisting: true\``
413+
`called \`inject\` to override already-existing reducer ${reducerPath} without specifying \`overrideExisting: true\``
498414
)
499415
}
500416

501417
return combinedReducer
502418
}
503419

504-
reducerMap[name] = reducerToInject
420+
reducerMap[reducerPath] = reducerToInject
505421

506422
reducer = getReducer()
507423

0 commit comments

Comments
 (0)