1
1
import { Reducer } from 'redux'
2
- import { createAction , PayloadAction , PayloadActionCreator } from './createAction'
3
- import { createReducer , CaseReducers } from './createReducer'
2
+ import {
3
+ createAction ,
4
+ PayloadAction ,
5
+ PayloadActionCreator ,
6
+ PrepareAction
7
+ } from './createAction'
8
+ import { createReducer , CaseReducers , CaseReducer } from './createReducer'
4
9
import { createSliceSelector , createSelectorName } from './sliceSelector'
5
10
6
11
/**
@@ -12,8 +17,8 @@ export type SliceActionCreator<P> = PayloadActionCreator<P>
12
17
13
18
export interface Slice <
14
19
S = any ,
15
- AP extends { [ key : string ] : any } = { [ key : string ] : any }
16
- > {
20
+ AC extends { [ key : string ] : any } = { [ key : string ] : any }
21
+ > {
17
22
/**
18
23
* The slice name.
19
24
*/
@@ -28,7 +33,7 @@ export interface Slice<
28
33
* Action creators for the types of actions that are handled by the slice
29
34
* reducer.
30
35
*/
31
- actions : { [ type in keyof AP ] : PayloadActionCreator < AP [ type ] > }
36
+ actions : AC
32
37
33
38
/**
34
39
* Selectors for the slice reducer state. `createSlice()` inserts a single
@@ -44,8 +49,8 @@ export interface Slice<
44
49
*/
45
50
export interface CreateSliceOptions <
46
51
S = any ,
47
- CR extends CaseReducers < S , any > = CaseReducers < S , any >
48
- > {
52
+ CR extends SliceCaseReducers < S , any > = SliceCaseReducers < S , any >
53
+ > {
49
54
/**
50
55
* The slice's name. Used to namespace the generated action types and to
51
56
* name the selector for retrieving the reducer's state.
@@ -72,12 +77,36 @@ export interface CreateSliceOptions<
72
77
extraReducers ?: CaseReducers < S , any >
73
78
}
74
79
75
- type CaseReducerActionPayloads < CR extends CaseReducers < any , any > > = {
80
+ type PayloadActions < T extends keyof any = string > = Record < T , PayloadAction >
81
+
82
+ type EnhancedCaseReducer < S , A extends PayloadAction > = {
83
+ reducer : CaseReducer < S , A >
84
+ prepare : PrepareAction < A [ 'payload' ] >
85
+ }
86
+
87
+ type SliceCaseReducers < S , PA extends PayloadActions > = {
88
+ [ T in keyof PA ] : CaseReducer < S , PA [ T ] > | EnhancedCaseReducer < S , PA [ T ] >
89
+ }
90
+
91
+ type CaseReducerActions < CR extends SliceCaseReducers < any , any > > = {
76
92
[ T in keyof CR ] : CR [ T ] extends ( state : any ) => any
77
- ? void
78
- : ( CR [ T ] extends ( state : any , action : PayloadAction < infer P > ) => any
79
- ? P
80
- : void )
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 > )
99
+ }
100
+
101
+ type NoInfer < T > = [ T ] [ T extends any ? 0 : never ] ;
102
+ 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
+ } : {
108
+
109
+ }
81
110
}
82
111
83
112
function getType ( slice : string , actionKey : string ) : string {
@@ -92,25 +121,36 @@ function getType(slice: string, actionKey: string): string {
92
121
*
93
122
* The `reducer` argument is passed to `createReducer()`.
94
123
*/
95
- export function createSlice < S , CR extends CaseReducers < S , any > > (
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 > > (
96
128
options : CreateSliceOptions < S , CR >
97
- ) : Slice < S , CaseReducerActionPayloads < CR > > {
129
+ ) : Slice < S , CaseReducerActions < CR > > {
98
130
const { slice = '' , initialState } = options
99
131
const reducers = options . reducers || { }
100
132
const extraReducers = options . extraReducers || { }
101
133
const actionKeys = Object . keys ( reducers )
102
134
103
135
const reducerMap = actionKeys . reduce ( ( map , actionKey ) => {
104
- map [ getType ( slice , actionKey ) ] = reducers [ actionKey ]
136
+ let maybeEnhancedReducer = reducers [ actionKey ]
137
+ map [ getType ( slice , actionKey ) ] =
138
+ typeof maybeEnhancedReducer === 'function'
139
+ ? maybeEnhancedReducer
140
+ : maybeEnhancedReducer . reducer
105
141
return map
106
142
} , extraReducers )
107
143
108
144
const reducer = createReducer ( initialState , reducerMap )
109
145
110
146
const actionMap = actionKeys . reduce (
111
147
( map , action ) => {
148
+ let maybeEnhancedReducer = reducers [ action ]
112
149
const type = getType ( slice , action )
113
- map [ action ] = createAction ( type )
150
+ map [ action ] =
151
+ typeof maybeEnhancedReducer === 'function'
152
+ ? createAction ( type )
153
+ : createAction ( type , maybeEnhancedReducer . prepare )
114
154
return map
115
155
} ,
116
156
{ } as any
0 commit comments