如何在Vue 3中搭配使用TypeScript、Composition API与带命名空间的Vuex 4
实现方案
完全可以在不引入额外依赖、保留TS类型约束的前提下兼容Vuex4命名空间,核心思路是通过TS模板字面量类型自动拼接命名空间前缀,或者封装子模块专属的store钩子,两种方案都符合你的要求:
方案A:封装子模块专属useStore钩子(推荐)
这种方案组件侧不需要感知命名空间,用法和无命名空间的模块完全一致,类型约束完整:
第一步:修改store.ts代码
// store.ts import {Store as VuexStore, createStore, Module, ActionTree} from "vuex"; // 定义模块命名空间常量,和注册模块时的key保持一致 const MODULE_NAMESPACE = 'module' as const; export enum ModuleActionTypes { Test = 'TEST' } interface ModuleActions { [ModuleActionTypes.Test]():void } const actions: ActionTree<any, any> & ModuleActions = { [ModuleActionTypes.Test]() : void { console.log("test action dispatched") } } const module: Module<any, any> = { namespaced: true, actions: actions } // 全局Store类型,保留原生Vuex Store的所有能力 type Store = VuexStore<any> const store = createStore<Store>({ modules: { module } }) // 全局原生useStore,有需要也可以导出 export function useStore(): Store { return store } // 子模块专属useStore,内部自动拼接命名空间前缀,类型完全匹配子模块定义 export function useModuleStore() { const globalStore = useStore() return { // 可以根据需要暴露state、getters、commit、dispatch等能力 dispatch: <K extends keyof ModuleActions>(key: K, payload?: any) => { return globalStore.dispatch(`${MODULE_NAMESPACE}/${key}`, payload) } } }
第二步:组件侧调用
// App.vue <script lang="ts"> import {defineComponent} from "vue"; import {ModuleActionTypes, useModuleStore} from "./store"; export default defineComponent({ name: 'App', setup() { const moduleStore = useModuleStore() // 直接传枚举值,TS会自动校验类型,不需要手动拼接前缀 moduleStore.dispatch(ModuleActionTypes.Test) } }) </script>
方案B:拓展全局Store的dispatch类型
如果不希望封装多个子模块钩子,可以直接通过TS的类型重载给全局dispatch加上所有带命名空间的action类型约束:
// store.ts 调整Store类型定义 type NamespacedModuleAction = `${typeof MODULE_NAMESPACE}/${ModuleActionTypes}` type Store = Omit<VuexStore<any>, 'dispatch'> & { dispatch<K extends keyof ModuleActions>( key: `${typeof MODULE_NAMESPACE}/${K}`, payload?: any ): ReturnType<ModuleActions[K]> // 有其他模块的话继续添加对应重载即可 }
组件侧调用时需要写全带前缀的action名,TS会自动校验合法性:
setup() { const store = useStore() store.dispatch('module/TEST') // 类型校验通过 store.dispatch(ModuleActionTypes.Test) // TS直接报错,提示不存在该action }
两种方案都完全符合你的要求:无额外第三方依赖、不使用类风格语法、保留完整的子模块类型约束、支持Vuex4命名空间配置。如果有多个子模块,只需要按规则新增对应模块的类型定义和钩子即可。
内容的提问来源于stack exchange,提问作者jen.pet
相关产品推荐
相关产品推荐

