11import { expect , it } from "vitest" ;
22import { Equal , Expect } from "../helpers/type-utils" ;
33
4- type HandlersToDiscriminatedUnion < T extends Record < string , any > > = {
4+ type PayloadsToDiscriminatedUnion < T extends Record < string , any > > = {
55 [ K in keyof T ] : { type : K } & T [ K ] ;
66} [ keyof T ] ;
77
88export class DynamicReducer <
99 TState ,
10- THandlers extends Record < string , any > = { } ,
10+ TPayloadMap extends Record < string , any > = { }
1111> {
1212 private handlers = { } as Record <
1313 string ,
14- ( state : TState , action : HandlersToDiscriminatedUnion < THandlers > ) => TState
14+ ( state : TState , payload : any ) => TState
1515 > ;
1616
17- addHandler < TType extends string , TPayload > (
17+ addHandler < TType extends string , TPayload extends object > (
1818 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 > > {
2121 this . handlers [ type ] = handler ;
2222
2323 return this ;
2424 }
2525
2626 reduce (
2727 state : TState ,
28- action : HandlersToDiscriminatedUnion < THandlers > ,
28+ action : PayloadsToDiscriminatedUnion < TPayloadMap >
2929 ) : TState {
3030 const handler = this . handlers [ action . type ] ;
3131 if ( ! handler ) {
@@ -49,19 +49,28 @@ const reducer = new DynamicReducer<State>()
4949 username : action . username ,
5050 password : action . password ,
5151 } ;
52- } ,
52+ }
5353 )
5454 . addHandler ( "LOG_OUT" , ( ) => {
5555 return {
5656 username : "" ,
5757 password : "" ,
5858 } ;
59+ } )
60+ . addHandler ( "UPDATE_USERNAME" , ( state , action : { username : string } ) => {
61+ return {
62+ ...state ,
63+ username : action . username ,
64+ } ;
5965 } ) ;
6066
6167it ( "Should return the new state after LOG_IN" , ( ) => {
6268 const state = reducer . reduce (
6369 { username : "" , password : "" } ,
64- { type : "LOG_IN" , username : "foo" , password : "bar" } ,
70+ {
71+ type : "UPDATE_USERNAME" ,
72+ username : "awdawdawd" ,
73+ }
6574 ) ;
6675
6776 type test = [ Expect < Equal < typeof state , State > > ] ;
@@ -72,7 +81,7 @@ it("Should return the new state after LOG_IN", () => {
7281it ( "Should return the new state after LOG_OUT" , ( ) => {
7382 const state = reducer . reduce (
7483 { username : "foo" , password : "bar" } ,
75- { type : "LOG_OUT" } ,
84+ { type : "LOG_OUT" }
7685 ) ;
7786
7887 type test = [ Expect < Equal < typeof state , State > > ] ;
@@ -86,7 +95,7 @@ it("Should error if you pass it an incorrect action", () => {
8695 {
8796 // @ts -expect-error
8897 type : "NOT_ALLOWED" ,
89- } ,
98+ }
9099 ) ;
91100} ) ;
92101
@@ -96,6 +105,6 @@ it("Should error if you pass an incorrect payload", () => {
96105 // @ts -expect-error
97106 {
98107 type : "LOG_IN" ,
99- } ,
108+ }
100109 ) ;
101110} ) ;
0 commit comments