@@ -8,13 +8,19 @@ import type {
8
8
ActionReducerMapBuilder ,
9
9
AsyncThunk ,
10
10
CaseReducer ,
11
+ CreatorCaseReducers ,
11
12
PayloadAction ,
12
13
PayloadActionCreator ,
13
14
Reducer ,
15
+ ReducerCreator ,
16
+ ReducerCreatorEntry ,
14
17
ReducerCreators ,
15
18
ReducerDefinition ,
19
+ ReducerHandlingContextMethods ,
20
+ ReducerNamesOfType ,
16
21
SerializedError ,
17
22
SliceCaseReducers ,
23
+ ThunkAction ,
18
24
ThunkDispatch ,
19
25
UnknownAction ,
20
26
ValidateSliceCaseReducers ,
@@ -27,9 +33,12 @@ import {
27
33
createAsyncThunk ,
28
34
createSlice ,
29
35
isRejected ,
36
+ nanoid ,
30
37
} from '@reduxjs/toolkit'
31
38
import { castDraft } from 'immer'
32
39
40
+ const toasterCreatorType = Symbol ( )
41
+
33
42
describe ( 'type tests' , ( ) => {
34
43
const counterSlice = createSlice ( {
35
44
name : 'counter' ,
@@ -983,4 +992,104 @@ describe('type tests', () => {
983
992
} ,
984
993
} )
985
994
} )
995
+ test ( 'creators can disable themselves if state is incompatible' , ( ) => {
996
+ const toastCreator : ReducerCreator < typeof toasterCreatorType > = {
997
+ type : toasterCreatorType ,
998
+ create : ( ) => ( {
999
+ _reducerDefinitionType : toasterCreatorType ,
1000
+ } ) ,
1001
+ handle ( { type, reducerName } , _definition , context ) {
1002
+ const toastOpened = createAction < { message : string ; id : string } > (
1003
+ type + '/opened' ,
1004
+ )
1005
+ const toastClosed = createAction < string > ( type + '/closed' )
1006
+ function openToast (
1007
+ ms : number ,
1008
+ message : string ,
1009
+ ) : ThunkAction < void , unknown , unknown , UnknownAction > {
1010
+ return ( dispatch , getState ) => {
1011
+ const id = nanoid ( )
1012
+ dispatch ( toastOpened ( { message, id } ) )
1013
+ setTimeout ( ( ) => {
1014
+ dispatch ( toastClosed ( id ) )
1015
+ } , ms )
1016
+ }
1017
+ }
1018
+ Object . assign ( openToast , { toastOpened, toastClosed } )
1019
+ ; ( context as ReducerHandlingContextMethods < ToastState > )
1020
+ . addCase ( toastOpened , ( state , { payload : { message, id } } ) => {
1021
+ state . toasts [ id ] = { message }
1022
+ } )
1023
+ . addCase ( toastClosed , ( state , action ) => {
1024
+ delete state . toasts [ action . payload ]
1025
+ } )
1026
+ . exposeAction ( reducerName , openToast )
1027
+ } ,
1028
+ }
1029
+
1030
+ const createAppSlice = buildCreateSlice ( {
1031
+ creators : { toaster : toastCreator } ,
1032
+ } )
1033
+
1034
+ const toastSlice = createAppSlice ( {
1035
+ name : 'toast' ,
1036
+ initialState : { toasts : { } } as ToastState ,
1037
+ reducers : ( create ) => ( {
1038
+ toast : create . toaster ( ) ,
1039
+ } ) ,
1040
+ } )
1041
+
1042
+ expectTypeOf ( toastSlice . actions . toast ) . toEqualTypeOf < AddToastThunk > ( )
1043
+
1044
+ expectTypeOf ( toastSlice . actions . toast ) . toBeCallableWith ( 100 , 'hello' )
1045
+
1046
+ const incompatibleSlice = createAppSlice ( {
1047
+ name : 'incompatible' ,
1048
+ initialState : { } ,
1049
+ reducers : ( create ) => {
1050
+ expectTypeOf ( create ) . not . toHaveProperty ( 'toaster' )
1051
+ return { }
1052
+ } ,
1053
+ } )
1054
+ } )
986
1055
} )
1056
+
1057
+ interface Toast {
1058
+ message : string
1059
+ }
1060
+
1061
+ interface ToastState {
1062
+ toasts : Record < string , Toast >
1063
+ }
1064
+
1065
+ interface AddToastThunk {
1066
+ (
1067
+ ms : number ,
1068
+ message : string ,
1069
+ ) : ThunkAction < void , unknown , unknown , UnknownAction >
1070
+ toastOpened : PayloadActionCreator < { message : string ; id : string } >
1071
+ toastClosed : PayloadActionCreator < string >
1072
+ }
1073
+
1074
+ declare module '@reduxjs/toolkit' {
1075
+ export interface SliceReducerCreators <
1076
+ State = any ,
1077
+ CaseReducers extends
1078
+ CreatorCaseReducers < State > = CreatorCaseReducers < State > ,
1079
+ Name extends string = string ,
1080
+ > {
1081
+ [ toasterCreatorType ] : ReducerCreatorEntry <
1082
+ State extends ToastState
1083
+ ? ( ) => ReducerDefinition < typeof toasterCreatorType >
1084
+ : never ,
1085
+ {
1086
+ actions : {
1087
+ [ ReducerName in ReducerNamesOfType <
1088
+ CaseReducers ,
1089
+ typeof toasterCreatorType
1090
+ > ] : AddToastThunk
1091
+ }
1092
+ }
1093
+ >
1094
+ }
1095
+ }
0 commit comments