33 createAction ,
44 PayloadAction ,
55 PayloadActionCreator ,
6- PrepareAction
6+ PrepareAction ,
7+ ActionCreatorWithoutPayload ,
8+ ActionCreatorWithPreparedPayload
79} from './createAction'
810import { createReducer , CaseReducers , CaseReducer } from './createReducer'
911import { createSliceSelector , createSelectorName } from './sliceSelector'
@@ -16,9 +18,9 @@ import { createSliceSelector, createSelectorName } from './sliceSelector'
1618export type SliceActionCreator < P > = PayloadActionCreator < P >
1719
1820export interface Slice <
19- S = any ,
20- AC extends { [ key : string ] : any } = { [ key : string ] : any }
21- > {
21+ State = any ,
22+ ActionCreators extends { [ key : string ] : any } = { [ key : string ] : any }
23+ > {
2224 /**
2325 * The slice name.
2426 */
@@ -27,30 +29,30 @@ export interface Slice<
2729 /**
2830 * The slice's reducer.
2931 */
30- reducer : Reducer < S >
32+ reducer : Reducer < State >
3133
3234 /**
3335 * Action creators for the types of actions that are handled by the slice
3436 * reducer.
3537 */
36- actions : AC
38+ actions : ActionCreators
3739
3840 /**
3941 * Selectors for the slice reducer state. `createSlice()` inserts a single
4042 * selector that returns the entire slice state and whose name is
4143 * automatically derived from the slice name (e.g., `getCounter` for a slice
4244 * named `counter`).
4345 */
44- selectors : { [ key : string ] : ( state : any ) => S }
46+ selectors : { [ key : string ] : ( state : any ) => State }
4547}
4648
4749/**
4850 * Options for `createSlice()`.
4951 */
5052export interface CreateSliceOptions <
51- S = any ,
52- CR extends SliceCaseReducers < S , any > = SliceCaseReducers < S , any >
53- > {
53+ State = any ,
54+ CR extends SliceCaseReducers < State , any > = SliceCaseReducers < State , any >
55+ > {
5456 /**
5557 * The slice's name. Used to namespace the generated action types and to
5658 * name the selector for retrieving the reducer's state.
@@ -60,7 +62,7 @@ export interface CreateSliceOptions<
6062 /**
6163 * The initial state to be returned by the slice reducer.
6264 */
63- initialState : S
65+ initialState : State
6466
6567 /**
6668 * A mapping from action types to action-type-specific *case reducer*
@@ -74,41 +76,54 @@ export interface CreateSliceOptions<
7476 * functions. These reducers should have existing action types used
7577 * as the keys, and action creators will _not_ be generated.
7678 */
77- extraReducers ?: CaseReducers < S , any >
79+ extraReducers ?: CaseReducers < State , any >
7880}
7981
80- type PayloadActions < T extends keyof any = string > = Record < T , PayloadAction >
82+ type PayloadActions < Types extends keyof any = string > = Record < Types , PayloadAction >
8183
82- type EnhancedCaseReducer < S , A extends PayloadAction > = {
83- reducer : CaseReducer < S , A >
84- prepare : PrepareAction < A [ 'payload' ] >
84+ type EnhancedCaseReducer < State , Action extends PayloadAction > = {
85+ reducer : CaseReducer < State , Action >
86+ prepare : PrepareAction < Action [ 'payload' ] >
8587}
8688
87- type SliceCaseReducers < S , PA extends PayloadActions > = {
88- [ T in keyof PA ] : CaseReducer < S , PA [ T ] > | EnhancedCaseReducer < S , PA [ T ] >
89+ type SliceCaseReducers < State , PA extends PayloadActions > = {
90+ [ ActionType in keyof PA ] : CaseReducer < State , PA [ ActionType ] > | EnhancedCaseReducer < State , PA [ ActionType ] >
8991}
9092
91- type CaseReducerActions < CR extends SliceCaseReducers < any , any > > = {
92- [ T in keyof CR ] : CR [ T ] extends ( state : any ) => any
93- ? PayloadActionCreator < void >
94- : ( CR [ T ] extends ( state : any , action : PayloadAction < infer P > ) => any
95- ? PayloadActionCreator < P >
96- : CR [ T ] extends { prepare : PrepareAction < infer P > }
97- ? PayloadActionCreator < P , string , CR [ T ] [ 'prepare' ] >
98- : PayloadActionCreator < void > )
93+ type IfIsReducerFunctionWithoutAction < R , True , False = never > = R extends ( state : any ) => any ? True : False ;
94+ type IfIsEnhancedReducer < R , True , False = never > = R extends { prepare : Function } ? True : False ;
95+
96+ type PayloadForReducer < R > = R extends ( state : any , action : PayloadAction < infer P > ) => any ? P : void ;
97+ type PrepareActionForReducer < R > = R extends { prepare : infer Prepare } ? Prepare : never ;
98+
99+ type CaseReducerActions < CaseReducers extends SliceCaseReducers < any , any > > = {
100+ [ Type in keyof CaseReducers ] :
101+ IfIsEnhancedReducer < CaseReducers [ Type ] ,
102+ ActionCreatorWithPreparedPayload < PrepareActionForReducer < CaseReducers [ Type ] > > ,
103+ // else
104+ IfIsReducerFunctionWithoutAction < CaseReducers [ Type ] ,
105+ ActionCreatorWithoutPayload ,
106+ // else
107+ PayloadActionCreator < PayloadForReducer < CaseReducers [ Type ] > >
108+ >
109+ >
99110}
100111
101112type NoInfer < T > = [ T ] [ T extends any ? 0 : never ] ;
113+
102114type SliceCaseReducersCheck < S , ACR > = {
103- [ P in keyof ACR ] : ACR [ P ] extends {
104- reducer ( s :S , action ?: { payload : infer O } ) : any
105- } ? {
106- prepare ( ...a :never [ ] ) : { payload : O }
107- } : {
115+ [ P in keyof ACR ] : ACR [ P ] extends {
116+ reducer ( s : S , action ?: { payload : infer O } ) : any
117+ } ? {
118+ prepare ( ...a : never [ ] ) : { payload : O }
119+ } : {
108120
109- }
121+ }
110122}
111123
124+ type RestrictEnhancedReducersToMatchReducerAndPrepare < S , CR extends SliceCaseReducers < S , any > > =
125+ { reducers : SliceCaseReducersCheck < S , NoInfer < CR > > } ;
126+
112127function getType ( slice : string , actionKey : string ) : string {
113128 return slice ? `${ slice } /${ actionKey } ` : actionKey
114129}
@@ -121,12 +136,14 @@ function getType(slice: string, actionKey: string): string {
121136 *
122137 * The `reducer` argument is passed to `createReducer()`.
123138 */
124- export function createSlice < S , CR extends SliceCaseReducers < S , any > > (
125- options : CreateSliceOptions < S , CR > & { reducers : SliceCaseReducersCheck < S , NoInfer < CR > > }
126- ) : Slice < S , CaseReducerActions < CR > >
127- export function createSlice < S , CR extends SliceCaseReducers < S , any > > (
128- options : CreateSliceOptions < S , CR >
129- ) : Slice < S , CaseReducerActions < CR > > {
139+ export function createSlice < State , CaseReducers extends SliceCaseReducers < State , any > > (
140+ options : CreateSliceOptions < State , CaseReducers > & RestrictEnhancedReducersToMatchReducerAndPrepare < State , CaseReducers >
141+ ) : Slice < State , CaseReducerActions < CaseReducers > >
142+
143+ // internal definition is a little less restrictive
144+ export function createSlice < State , CaseReducers extends SliceCaseReducers < State , any > > (
145+ options : CreateSliceOptions < State , CaseReducers >
146+ ) : Slice < State , CaseReducerActions < CaseReducers > > {
130147 const { slice = '' , initialState } = options
131148 const reducers = options . reducers || { }
132149 const extraReducers = options . extraReducers || { }
0 commit comments