Skip to content

Commit e3b8d90

Browse files
committed
expose selectSlice, name and reducerPath in context
1 parent 2e25c1f commit e3b8d90

File tree

1 file changed

+51
-11
lines changed

1 file changed

+51
-11
lines changed

packages/toolkit/src/createSlice.ts

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,11 @@ interface InternalReducerHandlingContext<State> {
190190
actionCreators: Record<string, any>
191191
}
192192

193-
export interface ReducerHandlingContext<State> {
193+
export interface ReducerHandlingContext<
194+
State,
195+
Name extends string,
196+
ReducerPath extends string,
197+
> {
194198
/**
195199
* Adds a case reducer to handle a single action type.
196200
* @param actionCreator - Either a plain action type string, or an action creator generated by [`createAction`](./createAction) that can be used to determine the action type.
@@ -199,7 +203,7 @@ export interface ReducerHandlingContext<State> {
199203
addCase<ActionCreator extends TypedActionCreator<string>>(
200204
actionCreator: ActionCreator,
201205
reducer: CaseReducer<State, ReturnType<ActionCreator>>,
202-
): ReducerHandlingContext<State>
206+
): ReducerHandlingContext<State, Name, ReducerPath>
203207
/**
204208
* Adds a case reducer to handle a single action type.
205209
* @param actionCreator - Either a plain action type string, or an action creator generated by [`createAction`](./createAction) that can be used to determine the action type.
@@ -208,7 +212,7 @@ export interface ReducerHandlingContext<State> {
208212
addCase<Type extends string, A extends Action<Type>>(
209213
type: Type,
210214
reducer: CaseReducer<State, A>,
211-
): ReducerHandlingContext<State>
215+
): ReducerHandlingContext<State, Name, ReducerPath>
212216

213217
/**
214218
* Allows you to match incoming actions against your own filter function instead of only the `action.type` property.
@@ -224,7 +228,7 @@ export interface ReducerHandlingContext<State> {
224228
addMatcher<A>(
225229
matcher: TypeGuard<A>,
226230
reducer: CaseReducer<State, A extends Action ? A : A & Action>,
227-
): ReducerHandlingContext<State>
231+
): ReducerHandlingContext<State, Name, ReducerPath>
228232
/**
229233
* Add an action to be exposed under the final `slice.actions[reducerName]` key.
230234
*
@@ -238,7 +242,10 @@ export interface ReducerHandlingContext<State> {
238242
*
239243
* dispatch(addPost(post))
240244
*/
241-
exposeAction(actionCreator: unknown): ReducerHandlingContext<State>
245+
exposeAction(
246+
actionCreator: unknown,
247+
): ReducerHandlingContext<State, Name, ReducerPath>
248+
242249
/**
243250
* Add a case reducer to be exposed under the final `slice.caseReducers[reducerName]` key.
244251
*
@@ -252,12 +259,34 @@ export interface ReducerHandlingContext<State> {
252259
*
253260
* slice.caseReducers.addPost([], addPost(post))
254261
*/
255-
exposeCaseReducer(reducer: unknown): ReducerHandlingContext<State>
262+
exposeCaseReducer(
263+
reducer: unknown,
264+
): ReducerHandlingContext<State, Name, ReducerPath>
265+
256266
/**
257267
* Provides access to the initial state value given to the slice.
258268
* If a lazy state initializer was provided, it will be called and a fresh value returned.
259269
*/
260270
getInitialState(): State
271+
272+
/**
273+
* The `name` option provided for the slice.
274+
*/
275+
name: Name
276+
277+
/**
278+
* The `reducerPath` option provided for the slice.
279+
* Defaults to `name` if not provided.
280+
*/
281+
reducerPath: ReducerPath
282+
283+
/**
284+
* Tries to select the slice's state from a possible root state shape, using `reducerPath`.
285+
* Throws an error if slice's state is not found.
286+
*
287+
* *Note that only the original `reducerPath` option is used - if a different `reducerPath` is used when injecting, this will not be reflected.*
288+
*/
289+
selectSlice(state: Record<ReducerPath, State>): State
261290
}
262291

263292
export interface ReducerDetails {
@@ -314,10 +343,10 @@ export type ReducerCreator<Type extends RegisteredReducerType> = {
314343
} & (ReducerDefinitionsForType<Type> extends never
315344
? {}
316345
: {
317-
handle<State>(
346+
handle<State, Name extends string, ReducerPath extends string>(
318347
details: ReducerDetails,
319348
definition: ReducerDefinitionsForType<Type>,
320-
context: ReducerHandlingContext<State>,
349+
context: ReducerHandlingContext<State, Name, ReducerPath>,
321350
): void
322351
})
323352

@@ -388,7 +417,7 @@ export interface Slice<
388417
* Equivalent to `slice.getSelectors((state: RootState) => state[slice.reducerPath])`.
389418
*/
390419
get selectors(): Id<
391-
SliceDefinedSelectors<State, Selectors, { [K in ReducerPath]: State }>
420+
SliceDefinedSelectors<State, Selectors, Record<ReducerPath, State>>
392421
>
393422

394423
/**
@@ -410,7 +439,7 @@ export interface Slice<
410439
*
411440
* Will throw an error if slice is not found.
412441
*/
413-
selectSlice(state: { [K in ReducerPath]: State }): State
442+
selectSlice(state: Record<ReducerPath, State>): State
414443
}
415444

416445
/**
@@ -898,7 +927,7 @@ export function buildCreateSlice<
898927
}
899928

900929
function getContext({ reducerName }: ReducerDetails) {
901-
const context: ReducerHandlingContext<State> = {
930+
const context: ReducerHandlingContext<State, Name, ReducerPath> = {
902931
addCase(
903932
typeOrActionCreator: string | TypedActionCreator<any>,
904933
reducer: CaseReducer<State>,
@@ -946,6 +975,17 @@ export function buildCreateSlice<
946975
return context
947976
},
948977
getInitialState,
978+
name,
979+
reducerPath,
980+
selectSlice(state) {
981+
const sliceState = state[reducerPath]
982+
if (typeof sliceState === 'undefined') {
983+
throw new Error(
984+
`Could not find "${name}" slice in state. In order for slice creators to use \`context.selectSlice\`, the slice must be nested in the state under its reducerPath: "${reducerPath}"`,
985+
)
986+
}
987+
return sliceState
988+
},
949989
}
950990
return context
951991
}

0 commit comments

Comments
 (0)