1
1
import { expect , it } from "vitest" ;
2
2
import { Equal , Expect } from "../helpers/type-utils" ;
3
3
4
- type HandlersToDiscriminatedUnion < T extends Record < string , any > > = {
4
+ type PayloadsToDiscriminatedUnion < T extends Record < string , any > > = {
5
5
[ K in keyof T ] : { type : K } & T [ K ] ;
6
6
} [ keyof T ] ;
7
7
8
8
export class DynamicReducer <
9
9
TState ,
10
- THandlers extends Record < string , any > = { } ,
10
+ TPayloadMap extends Record < string , any > = { }
11
11
> {
12
12
private handlers = { } as Record <
13
13
string ,
14
- ( state : TState , action : HandlersToDiscriminatedUnion < THandlers > ) => TState
14
+ ( state : TState , payload : any ) => TState
15
15
> ;
16
16
17
- addHandler < TType extends string , TPayload > (
17
+ addHandler < TType extends string , TPayload extends object > (
18
18
type : TType ,
19
- handler : ( state : TState , payload : TPayload ) => TState ,
20
- ) : DynamicReducer < TState , THandlers & Record < TType , TPayload > > {
19
+ handler : ( state : TState , payload : TPayload ) => TState
20
+ ) : DynamicReducer < TState , TPayloadMap & Record < TType , TPayload > > {
21
21
this . handlers [ type ] = handler ;
22
22
23
23
return this ;
24
24
}
25
25
26
26
reduce (
27
27
state : TState ,
28
- action : HandlersToDiscriminatedUnion < THandlers > ,
28
+ action : PayloadsToDiscriminatedUnion < TPayloadMap >
29
29
) : TState {
30
30
const handler = this . handlers [ action . type ] ;
31
31
if ( ! handler ) {
@@ -49,19 +49,28 @@ const reducer = new DynamicReducer<State>()
49
49
username : action . username ,
50
50
password : action . password ,
51
51
} ;
52
- } ,
52
+ }
53
53
)
54
54
. addHandler ( "LOG_OUT" , ( ) => {
55
55
return {
56
56
username : "" ,
57
57
password : "" ,
58
58
} ;
59
+ } )
60
+ . addHandler ( "UPDATE_USERNAME" , ( state , action : { username : string } ) => {
61
+ return {
62
+ ...state ,
63
+ username : action . username ,
64
+ } ;
59
65
} ) ;
60
66
61
67
it ( "Should return the new state after LOG_IN" , ( ) => {
62
68
const state = reducer . reduce (
63
69
{ username : "" , password : "" } ,
64
- { type : "LOG_IN" , username : "foo" , password : "bar" } ,
70
+ {
71
+ type : "UPDATE_USERNAME" ,
72
+ username : "awdawdawd" ,
73
+ }
65
74
) ;
66
75
67
76
type test = [ Expect < Equal < typeof state , State > > ] ;
@@ -72,7 +81,7 @@ it("Should return the new state after LOG_IN", () => {
72
81
it ( "Should return the new state after LOG_OUT" , ( ) => {
73
82
const state = reducer . reduce (
74
83
{ username : "foo" , password : "bar" } ,
75
- { type : "LOG_OUT" } ,
84
+ { type : "LOG_OUT" }
76
85
) ;
77
86
78
87
type test = [ Expect < Equal < typeof state , State > > ] ;
@@ -86,7 +95,7 @@ it("Should error if you pass it an incorrect action", () => {
86
95
{
87
96
// @ts -expect-error
88
97
type : "NOT_ALLOWED" ,
89
- } ,
98
+ }
90
99
) ;
91
100
} ) ;
92
101
@@ -96,6 +105,6 @@ it("Should error if you pass an incorrect payload", () => {
96
105
// @ts -expect-error
97
106
{
98
107
type : "LOG_IN" ,
99
- } ,
108
+ }
100
109
) ;
101
110
} ) ;
0 commit comments