3
3
createAction ,
4
4
PayloadAction ,
5
5
PayloadActionCreator ,
6
- PrepareAction
6
+ PrepareAction ,
7
+ ActionCreatorWithoutPayload ,
8
+ ActionCreatorWithPreparedPayload
7
9
} from './createAction'
8
10
import { createReducer , CaseReducers , CaseReducer } from './createReducer'
9
11
import { createSliceSelector , createSelectorName } from './sliceSelector'
@@ -16,9 +18,9 @@ import { createSliceSelector, createSelectorName } from './sliceSelector'
16
18
export type SliceActionCreator < P > = PayloadActionCreator < P >
17
19
18
20
export 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
+ > {
22
24
/**
23
25
* The slice name.
24
26
*/
@@ -27,30 +29,30 @@ export interface Slice<
27
29
/**
28
30
* The slice's reducer.
29
31
*/
30
- reducer : Reducer < S >
32
+ reducer : Reducer < State >
31
33
32
34
/**
33
35
* Action creators for the types of actions that are handled by the slice
34
36
* reducer.
35
37
*/
36
- actions : AC
38
+ actions : ActionCreators
37
39
38
40
/**
39
41
* Selectors for the slice reducer state. `createSlice()` inserts a single
40
42
* selector that returns the entire slice state and whose name is
41
43
* automatically derived from the slice name (e.g., `getCounter` for a slice
42
44
* named `counter`).
43
45
*/
44
- selectors : { [ key : string ] : ( state : any ) => S }
46
+ selectors : { [ key : string ] : ( state : any ) => State }
45
47
}
46
48
47
49
/**
48
50
* Options for `createSlice()`.
49
51
*/
50
52
export 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
+ > {
54
56
/**
55
57
* The slice's name. Used to namespace the generated action types and to
56
58
* name the selector for retrieving the reducer's state.
@@ -60,7 +62,7 @@ export interface CreateSliceOptions<
60
62
/**
61
63
* The initial state to be returned by the slice reducer.
62
64
*/
63
- initialState : S
65
+ initialState : State
64
66
65
67
/**
66
68
* A mapping from action types to action-type-specific *case reducer*
@@ -74,41 +76,54 @@ export interface CreateSliceOptions<
74
76
* functions. These reducers should have existing action types used
75
77
* as the keys, and action creators will _not_ be generated.
76
78
*/
77
- extraReducers ?: CaseReducers < S , any >
79
+ extraReducers ?: CaseReducers < State , any >
78
80
}
79
81
80
- type PayloadActions < T extends keyof any = string > = Record < T , PayloadAction >
82
+ type PayloadActions < Types extends keyof any = string > = Record < Types , PayloadAction >
81
83
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' ] >
85
87
}
86
88
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 ] >
89
91
}
90
92
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
+ >
99
110
}
100
111
101
112
type NoInfer < T > = [ T ] [ T extends any ? 0 : never ] ;
113
+
102
114
type 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
+ } : {
108
120
109
- }
121
+ }
110
122
}
111
123
124
+ type RestrictEnhancedReducersToMatchReducerAndPrepare < S , CR extends SliceCaseReducers < S , any > > =
125
+ { reducers : SliceCaseReducersCheck < S , NoInfer < CR > > } ;
126
+
112
127
function getType ( slice : string , actionKey : string ) : string {
113
128
return slice ? `${ slice } /${ actionKey } ` : actionKey
114
129
}
@@ -121,12 +136,14 @@ function getType(slice: string, actionKey: string): string {
121
136
*
122
137
* The `reducer` argument is passed to `createReducer()`.
123
138
*/
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 > > {
130
147
const { slice = '' , initialState } = options
131
148
const reducers = options . reducers || { }
132
149
const extraReducers = options . extraReducers || { }
0 commit comments