我目前正在尝试创建一个 Vue 3 应用程序,该应用程序利用以 TypeScript 编写的 Vuex 4(命名空间)的 Composition API。
有很多不同的方法,但到目前为止,它们都不是很有用。我不想为此使用任何类样式语法或不必要的外部包装器。
这是一个向您展示我的问题的最小示例:
// 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
}
有趣或棘手的部分是从应用程序角度调用。我尝试了几种不同结果的方法。
方法 1(失败):createNamespacedHelpers()
使用mapActions
或来自 vuex 包的
内置功能useActions
不起作用,因为它需要设置 this.$store,而 Vue 3(Composition API)和 Vuex 4 并非如此。
方法 2(失败):
使用vuex-composition-helpers
需要依赖于@vue/composition-api
Vue 3 依赖关系图时会导致依赖关系噩梦。
方法 3(失败):
更接近代码:利用 typedModuleActionTypes
来调度操作会导致[vuex] unknown action type: TEST
错误,因为useStore()
返回的是通用存储而不是子模块。从模块中删除命名空间显然会使其工作。
...
// 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>
...
方法 4(工作): “取消键入”模块的存储并使用纯字符串来调度操作。
// store.ts
...
type ModuleStore = VuexStore<any>
...
// App.vue
...
setup() {
const store = useStore()
store.dispatch(`module/${ModuleActionTypes.Test}`)
}
...
此外,可以使用内部和外部操作类型@see 47646176来避免 Vue 组件中的字符串连接。
是否有任何想法或建议仍然可以键入子模块的存储并且命名空间到位?