1
1
import { useSyncExternalStore } from 'react' ;
2
2
3
- type SetStateAction < Value > = ( ( prev : Value ) => Value ) | Value ;
3
+ type SetStateAction < Value > = ( ( prev : Value ) => Partial < Value > ) | Partial < Value > ;
4
+
5
+ type Listener < Value > = ( state : Value , prevState : Value ) => void ;
6
+
4
7
type StateCreator < Value > = (
5
8
set : ( action : SetStateAction < Value > ) => void ,
6
9
get : ( ) => Value
7
10
) => Value ;
8
11
12
+ function isStateCreator < Value > ( fn : unknown ) : fn is StateCreator < Value > {
13
+ return typeof fn === 'function' ;
14
+ }
15
+
16
+ function isActionFunction < Value > ( fn : unknown ) : fn is ( prev : Value ) => Partial < Value > {
17
+ return typeof fn === 'function' ;
18
+ }
19
+
9
20
export interface StoreApi < Value > {
10
21
getInitialState : ( ) => Value ;
11
22
getState : ( ) => Value ;
@@ -29,40 +40,48 @@ export interface StoreApi<Value> {
29
40
* }));
30
41
*/
31
42
export const createStore = < Value > ( createState : StateCreator < Value > | Value ) => {
32
- type Listener = ( state : Value , prevState : Value ) => void ;
33
43
let state : Value ;
34
- const listeners : Set < Listener > = new Set ( ) ;
44
+ const listeners : Set < Listener < Value > > = new Set ( ) ;
35
45
36
- const setState = ( action : SetStateAction < Value > ) => {
37
- const nextState =
38
- typeof action === 'function' ? ( action as ( state : Value ) => Value ) ( state ) : action ;
46
+ const setState : StoreApi < Value > [ 'setState' ] = ( action : SetStateAction < Value > ) => {
47
+ const nextState = isActionFunction < Value > ( action ) ? action ( state ) : action ;
39
48
40
49
if ( ! Object . is ( nextState , state ) ) {
41
50
const prevState = state ;
42
- state = nextState ;
51
+ state =
52
+ typeof nextState !== 'object' || nextState === null
53
+ ? nextState
54
+ : Object . assign ( { } , state , nextState ) ;
55
+
43
56
listeners . forEach ( ( listener ) => listener ( state , prevState ) ) ;
44
57
}
45
58
} ;
46
59
47
- const getState = ( ) => state ;
48
- const getInitialState = ( ) => state ;
49
-
50
- const subscribe = ( listener : Listener ) => {
60
+ const subscribe = ( listener : Listener < Value > ) => {
51
61
listeners . add ( listener ) ;
62
+
52
63
return ( ) => listeners . delete ( listener ) ;
53
64
} ;
54
- if ( typeof createState === 'function' ) {
55
- state = ( createState as StateCreator < Value > ) ( setState , getState ) ;
65
+
66
+ const getState = ( ) => state ;
67
+ const getInitialState = ( ) => state ;
68
+
69
+ if ( isStateCreator < Value > ( createState ) ) {
70
+ state = createState ( setState , getState ) ;
56
71
} else {
57
72
state = createState ;
58
73
}
59
74
60
- const useStore = < Selected > ( selector ?: ( state : Value ) => Selected ) =>
61
- useSyncExternalStore (
75
+
76
+ function useStore ( ) : Value ;
77
+ function useStore < Selected > ( selector : ( state : Value ) => Selected ) : Selected ;
78
+ function useStore < Selected > ( selector ?: ( state : Value ) => Selected ) : Selected | Value {
79
+ return useSyncExternalStore (
62
80
subscribe ,
63
81
( ) => ( selector ? selector ( getState ( ) ) : getState ( ) ) ,
64
82
( ) => ( selector ? selector ( getInitialState ( ) ) : getInitialState ( ) )
65
83
) ;
84
+ }
66
85
67
86
return {
68
87
set : setState ,
0 commit comments