1
1
import * as React from 'react'
2
- import { Params , DropFirst } from 'src/helperTypes'
3
2
4
- type Action < TState , TArgs extends any [ ] = any , TReturn = void > =
5
- ( setState : React . Dispatch < React . SetStateAction < TState > > , ...args : TArgs ) => TReturn
3
+ /*
4
+ Custom Helper types
5
+ */
6
+
7
+ // Custom Params helper type because existing counterpart "Parameters" uses any instead of never, which is faulsy
8
+ export type Params < T extends ( ...args : never [ ] ) => unknown > = T extends ( ...args : infer P ) => any ? P : never ;
9
+
10
+ // Custom RetType helper type because existing counterpart "ReturnType" uses any instead of never, which is faulsy
11
+ export type RetType < T extends ( ...args : never [ ] ) => unknown > = T extends ( ...args : never [ ] ) => infer R ? R : any ;
12
+
13
+ // For [First, ...Rest] tuple gets [Rest] tuple
14
+ export type DropFirst < T extends any [ ] > =
15
+ ( ( ...args : T ) => any ) extends ( arg : any , ...rest : infer U ) => any [ ] ? U : T ;
16
+
17
+ export type Tail < T > = T extends Array < any >
18
+ ? ( ( ...args : T ) => never ) extends ( ( a : any , ...args : infer R ) => never )
19
+ ? R
20
+ : never
21
+ : never
22
+
23
+ /*
24
+ API Types
25
+ */
26
+
27
+ type ContextReference < TState > = {
28
+ setState : React . Dispatch < React . SetStateAction < TState > >
29
+ useContext : < T > ( context : React . Context < T > ) => T
30
+ }
31
+
32
+ type Action < TState , TArgs extends never [ ] = never [ ] , TReturn = any > =
33
+ ( contextReference : ContextReference < TState > , ...args : TArgs ) => TReturn
6
34
7
35
type Actions < TState > = { [ key : string ] : Action < TState > }
8
36
9
37
type MappedActions < TState , TActions extends Actions < TState > > = {
10
- [ P in keyof TActions ] : ( ...args : DropFirst < Params < TActions [ P ] > > ) => ReturnType < TActions [ P ] >
38
+ [ P in keyof TActions ] : ( ...args : DropFirst < Params < TActions [ P ] > > ) => RetType < TActions [ P ] >
11
39
}
12
40
13
41
type Store < TState , TActions extends Actions < TState > > =
14
42
TActions extends undefined ? TState : TState & MappedActions < TState , TActions >
15
43
44
+ /*
45
+ Logic
46
+ */
47
+
16
48
export default function createStateContext < TState , TActions extends Actions < TState > = { } > (
17
49
initialState : TState ,
18
50
actions ?: TActions
@@ -22,8 +54,11 @@ export default function createStateContext<TState, TActions extends Actions<TSta
22
54
23
55
const provider : React . FC = props => {
24
56
let [ _state , setState ] = React . useState ( initialState )
25
-
26
- const _actions = mapActionsToDispatch ( setState , actions )
57
+ const useContext = React . useContext
58
+ const _actions = mapActionsToDispatch ( {
59
+ setState,
60
+ useContext
61
+ } , actions )
27
62
28
63
const _store = { ..._state , ..._actions } as Store < TState , TActions >
29
64
@@ -38,15 +73,16 @@ export default function createStateContext<TState, TActions extends Actions<TSta
38
73
}
39
74
40
75
function mapActionsToDispatch < TState , TActions extends Actions < TState > > (
41
- dispatch : React . Dispatch < React . SetStateAction < TState > > ,
76
+ contextReference : ContextReference < TState > ,
42
77
actions ?: TActions ,
43
78
) : MappedActions < TState , TActions > {
44
79
if ( actions === undefined ) return { } as MappedActions < TState , TActions >
45
80
return Object . keys ( actions ) . reduce (
46
81
( obj , key ) => {
82
+ const action = actions [ key ]
47
83
return {
48
84
...obj ,
49
- [ key ] : ( ...payload : never [ ] ) => actions [ key ] ( dispatch , payload [ 0 ] )
85
+ [ key ] : ( ...args : never [ ] ) => actions [ key ] ( contextReference , ... args )
50
86
}
51
87
} ,
52
88
{ } as MappedActions < TState , TActions > )
@@ -60,8 +96,7 @@ function mapActionsToDefault<TState, TActions extends Actions<TState>>(
60
96
( obj , key ) => {
61
97
return {
62
98
...obj ,
63
- [ key ] : ( ...payload : never [ ] ) =>
64
- ( ) => { throw new Error ( `Can't invoke ${ key } because provider does not exist` ) }
99
+ [ key ] : ( ...args : never [ ] ) => { throw new Error ( `Can't invoke ${ key } because provider does not exist` ) }
65
100
}
66
101
} ,
67
102
{ } as MappedActions < TState , TActions > )
0 commit comments