I'm currently trying to create a Vue 3 Application that utilizes the Composition API with Vuex 4 (namespaced) written in TypeScript.
There are tons of different approaches but none of them look very useable as of now. I don't want to use any class style syntax or unnecessary external wrappers for this.
Here's a minimal example to show you my issues:
// package.json
"vue": "^3.0.0",
"vuex": "^4.0.2"
// store.ts
import {Store as VuexStore, createStore, Module, ActionTree} from "vuex";
export enum ModuleActionTypes {
Test = 'TEST'
}
interface ModuleActions {
[ModuleActionTypes.Test]():void
}
const actions: ActionTree<any, any> & ModuleActions = {
[ModuleActionTypes.Test]() : void {
console.log("test action dispatched")
}
}
type ModuleStore = Omit<VuexStore<any>, 'dispatch'>
& {
dispatch<K extends keyof ModuleActions>(
key: K
): ReturnType<ModuleActions[K]>
}
const module: Module<any, any> = {
namespaced: true,
actions: actions
}
type Store = ModuleStore
const store = createStore<Store>({
modules: {
module
}
})
export function useStore(): Store {
return store
}
The interesting or tricky part is the invocation from an app perspective. I've tried several approaches with different outcomes.
Approach 1 (failed):
Built-in createNamespacedHelpers() with mapActions or useActions from the vuex package do not work since it requires this.$store to be set which is not the case with Vue 3 (Composition API) and Vuex 4.
Approach 2 (failed):
Utilizing vuex-composition-helpers requires the dependency to the @vue/composition-api which causes a dependency nightmare when including into the Vue 3 dependency graph.
Approach 3 (failed):
Moving closer to code: utilizing the typed ModuleActionTypes to dispatch an action results in a [vuex] unknown action type: TEST error since useStore() returns the general store instead of the submodule. Removing the namespace from the module would obviously make it work.
...
// App.vue
<script lang="ts">
import {defineComponent} from "vue";
import {ModuleActionTypes, useStore} from "./store";
export default defineComponent({
name: 'App',
setup() {
const store = useStore()
store.dispatch(ModuleActionTypes.Test)
}
})
</script>
...
Approach 4 (working): "un-type" the module's store and use a plain string to dispatch the action.
// store.ts
...
type ModuleStore = VuexStore<any>
...
// App.vue
...
setup() {
const store = useStore()
store.dispatch(`module/${ModuleActionTypes.Test}`)
}
...
Additionally, internal and external action types could be used @see 47646176 to avoid the string concatenation within the Vue component.
Are there any ideas or suggestions where the store of the submodule can still be typed and namespaces are in place?