1
1
2
- import { ActionContext , ActionTree , GetterTree , Module , MutationTree , Store } from "vuex"
2
+ import { ActionContext , ActionTree , GetterTree , Module , MutationTree , Store , StoreOptions , ModuleTree } from "vuex"
3
3
4
4
const useRootNamespace = { root : true }
5
5
@@ -15,14 +15,16 @@ export interface BareActionContext<S, R>
15
15
rootState : R
16
16
}
17
17
18
- export class ModuleBuilder < S , R > {
19
- private store : RootStore < R >
18
+ class ModuleBuilderImpl < S , R = { } > implements ModuleBuilder < S , R > {
19
+ private _store : RootStore < R >
20
20
21
- private getters : GetterTree < S , R > = { }
22
- private mutations : MutationTree < S > = { }
23
- private actions : ActionTree < S , R > = { }
21
+ private _getters : GetterTree < S , R > = { }
22
+ private _mutations : MutationTree < S > = { }
23
+ private _actions : ActionTree < S , R > = { }
24
24
25
- constructor ( private namespace : string , private state : S ) { }
25
+ private _vuexModule : Module < S , R > | undefined
26
+
27
+ constructor ( public readonly namespace : string , private state : S ) { }
26
28
27
29
commit < P > ( handler : MutationHandler < S , void > ) : ( ) => void
28
30
commit < P > ( handler : MutationHandler < S , P > ) : ( payload : P ) => void
@@ -31,8 +33,8 @@ export class ModuleBuilder<S, R> {
31
33
commit < P > ( handler : MutationHandler < S , P > , name ?: string )
32
34
{
33
35
const { key, namespacedKey } = qualifyKey ( handler , this . namespace , name )
34
- this . mutations [ key ] = handler
35
- return ( ( payload : P ) => this . store . commit ( namespacedKey , payload , useRootNamespace ) ) as any
36
+ this . _mutations [ key ] = handler
37
+ return ( ( payload : P ) => this . _store . commit ( namespacedKey , payload , useRootNamespace ) ) as any
36
38
}
37
39
38
40
dispatch < P , T > ( handler : ActionHandler < S , R , void , void > ) : ( ) => Promise < void >
@@ -46,40 +48,44 @@ export class ModuleBuilder<S, R> {
46
48
dispatch < P , T > ( handler : any , name ?: string ) : any
47
49
{
48
50
const { key, namespacedKey } = qualifyKey ( handler , this . namespace , name )
49
- this . actions [ key ] = handler
50
- return ( payload : P ) => this . store . dispatch ( namespacedKey , payload , useRootNamespace )
51
+ this . _actions [ key ] = handler
52
+ return ( payload : P ) => this . _store . dispatch ( namespacedKey , payload , useRootNamespace )
51
53
}
52
54
53
55
read < T > ( handler : GetterHandler < S , R , T > ) : ( ) => T
54
56
read < T > ( handler : GetterHandler < S , R , T > , name : string ) : ( ) => T
55
57
read < T > ( handler : GetterHandler < S , R , T > , name ?: string ) : ( ) => T
56
58
{
57
59
const { key, namespacedKey } = qualifyKey ( handler , this . namespace , name )
58
- this . getters [ key ] = handler
60
+ this . _getters [ key ] = handler
59
61
return ( ) =>
60
62
{
61
- if ( this . store . rootGetters )
63
+ if ( this . _store . rootGetters )
62
64
{
63
- return this . store . rootGetters [ namespacedKey ] as T
65
+ return this . _store . rootGetters [ namespacedKey ] as T
64
66
}
65
- return this . store . getters [ namespacedKey ] as T
67
+ return this . _store . getters [ namespacedKey ] as T
66
68
}
67
69
}
68
70
69
- provideStore ( ) : ( store : Store < R > ) => void
71
+ vuexModule ( ) : Module < S , R >
70
72
{
71
- return ( store ) => this . store = store
73
+ if ( ! this . _vuexModule )
74
+ {
75
+ this . _vuexModule = {
76
+ namespaced : true ,
77
+ state : this . state ,
78
+ getters : this . _getters ,
79
+ mutations : this . _mutations ,
80
+ actions : this . _actions
81
+ }
82
+ }
83
+ return this . _vuexModule
72
84
}
73
85
74
- toVuexModule ( ) : Module < S , R >
86
+ _provideStore ( store : Store < R > )
75
87
{
76
- return {
77
- namespaced : true ,
78
- state : this . state ,
79
- getters : this . getters ,
80
- mutations : this . mutations ,
81
- actions : this . actions
82
- }
88
+ this . _store = store
83
89
}
84
90
}
85
91
@@ -91,4 +97,101 @@ function qualifyKey(handler: Function, namespace: string | undefined, name?: str
91
97
throw new Error ( `Vuex handler functions must not be anonymous. Possible causes: fat-arrow functions, uglify` )
92
98
}
93
99
return namespace ? { key, namespacedKey : `${ namespace } /${ key } ` } : { key, namespacedKey : key }
100
+ }
101
+
102
+ export interface ModuleBuilder < S , R = { } >
103
+ {
104
+ /** The namespace of this ModuleBuilder */
105
+ readonly namespace : string
106
+
107
+ /** Returns a strongly-typed commit function for the provided mutation handler */
108
+ commit < P > ( handler : MutationHandler < S , void > ) : ( ) => void
109
+ commit < P > ( handler : MutationHandler < S , P > ) : ( payload : P ) => void
110
+ commit < P > ( handler : MutationHandler < S , void > , name : string ) : ( ) => void
111
+ commit < P > ( handler : MutationHandler < S , P > , name : string ) : ( payload : P ) => void
112
+
113
+ /** Returns a strongly-typed dispatch function for the provided action handler */
114
+ dispatch < P , T > ( handler : ActionHandler < S , R , void , void > ) : ( ) => Promise < void >
115
+ dispatch < P , T > ( handler : ActionHandler < S , R , P , void > ) : ( payload : P ) => Promise < void >
116
+ dispatch < P , T > ( handler : ActionHandler < S , R , void , T > ) : ( ) => Promise < T >
117
+ dispatch < P , T > ( handler : ActionHandler < S , R , P , T > ) : ( payload : P ) => Promise < T >
118
+ dispatch < P , T > ( handler : ActionHandler < S , R , void , void > , name : string ) : ( ) => Promise < void >
119
+ dispatch < P , T > ( handler : ActionHandler < S , R , P , void > , name : string ) : ( payload : P ) => Promise < void >
120
+ dispatch < P , T > ( handler : ActionHandler < S , R , void , T > , name : string ) : ( ) => Promise < T >
121
+ dispatch < P , T > ( handler : ActionHandler < S , R , P , T > , name : string ) : ( payload : P ) => Promise < T >
122
+
123
+ /** Returns a strongly-typed read function for the provided getter function */
124
+ read < T > ( handler : GetterHandler < S , R , T > ) : ( ) => T
125
+ read < T > ( handler : GetterHandler < S , R , T > , name : string ) : ( ) => T
126
+
127
+ /** Returns a Vuex Module. Called after all strongly-typed functions have been obtained */
128
+ vuexModule ( ) : Module < S , R >
129
+
130
+ _provideStore ( store : Store < R > ) : void
131
+ }
132
+
133
+ class StoreBuilderImpl < R > implements StoreBuilder < R > {
134
+ private _moduleBuilders : ModuleBuilder < any , R > [ ] = [ ]
135
+ private _vuexStore : Store < R > | undefined
136
+
137
+ constructor ( ) { }
138
+
139
+ module < S > ( namespace : string , state : S ) : ModuleBuilder < S , R >
140
+ {
141
+ if ( this . _vuexStore )
142
+ {
143
+ throw new Error ( "Can't call module() after vuexStore() has been called" )
144
+ }
145
+ const builder = new ModuleBuilderImpl < S , R > ( namespace , state )
146
+ this . _moduleBuilders . push ( builder )
147
+ return builder
148
+ }
149
+
150
+ vuexStore ( ) : Store < R >
151
+ {
152
+ if ( ! this . _vuexStore )
153
+ {
154
+ const options : StoreOptions < R > = this . createStoreOptions ( )
155
+ const store = new Store < R > ( options )
156
+ this . _moduleBuilders . forEach ( m => m . _provideStore ( store ) )
157
+ this . _vuexStore = store
158
+ }
159
+ return this . _vuexStore
160
+ }
161
+
162
+ private createStoreOptions ( ) : StoreOptions < R >
163
+ {
164
+ const modules : ModuleTree < R > = { }
165
+ this . _moduleBuilders . forEach ( m => modules [ m . namespace ] = m . vuexModule ( ) )
166
+ return { modules }
167
+ }
168
+ }
169
+
170
+ export interface StoreBuilder < R >
171
+ {
172
+ /** Get a ModuleBuilder for the namespace provided */
173
+ module < S > ( namespace : string , state : S ) : ModuleBuilder < S , R >
174
+
175
+ /** Output a Vuex Store after all modules have been built */
176
+ vuexStore ( ) : Store < R >
177
+ }
178
+
179
+ const storeBuilderSingleton = new StoreBuilderImpl < any > ( )
180
+ const namedStoreBuilderMap : { [ name : string ] : StoreBuilderImpl < any > } = Object . create ( null )
181
+
182
+ /** Get a reference to the default store builder */
183
+ export function getStoreBuilder < R > ( ) : StoreBuilder < R >
184
+ /** Get a reference to a named store builder */
185
+ export function getStoreBuilder < R > ( name : string ) : StoreBuilder < R >
186
+ export function getStoreBuilder < R > ( name ?: string ) : StoreBuilder < R >
187
+ {
188
+ // the default store builder
189
+ if ( ! name )
190
+ {
191
+ return storeBuilderSingleton
192
+ }
193
+
194
+ // a named store builder
195
+ const builder = namedStoreBuilderMap [ name ] || ( namedStoreBuilderMap [ name ] = new StoreBuilderImpl < R > ( ) )
196
+ return builder
94
197
}
0 commit comments