V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
zcf0508
V2EX  ›  分享创造

已经 2023 年了,给 vuex 补充类型还值得吗

  •  
  •   zcf0508 ·
    zcf0508 · 2023-08-19 15:37:46 +08:00 · 2201 次点击
    这是一个创建于 460 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一转眼已经 2023 年了,vue2 即将在年底寿终正寝。但是现在谁手里还没有几个 vue2 的项目呢。在 vue3 全面拥抱 ts 的时刻,我希望我手里的这个 vue2 项目也能够更好的类型提示,有更好的开发体验。

    在最近改造项目的过程中,愈发觉得 vuex 是 vue2 全面拥抱 ts 的一大阻碍。vuex 在设计之初就没有考虑类型,导致无论是定义 Module 或者在组件中使用 mapX 函数,都会导致页面出现大量的类型错误。

    💐经过几天的努力,我初步完成了更好用的带类型的 vuex。项目详情请跳转 z-vuex-typed

    设计初衷

    1. 提供完善的类型提示

    完善的类型提示包括在定义 Module 和 Store 时,能够对 mutations 、actions 、getters 的函数参数有足够的类型提示。还包括在使用 mapX 函数时,能够提供参数的可选值,并且在组件内使用 mapX 函数时,组件也能正确知道引入的数据和方法的类型。

    1. 尽量简单的迁移过程

    我不希望引入这个项目会给原项目带来过多的改造,这就是为什么不选择使用 pinia 重构项目的原因。这个项目只引入两个新的方法 defineModuledefineStore 作为包装,以便正确获得类型推断。

    1. 不改变 vuex 的行为

    这个项目只覆盖默认 vuex 的类型,即使类型出错,也完全不会导致 vuex 的行为异常,这使得给 vuex 增加类型不会造成任何的副作用。

    安装

    为了覆盖 vuex 的类型,需要在安装 z-vuex-typed 的同时卸载 vuex ,避免类型冲突

    npm uninstall vuex
    npm install z-vuex-typed
    

    使用方法

    1. 使用 defineModule 定义 Modules
    import { defineModule } from 'z-vuex-typed'
    
    const userModule = defineModule({
        // ... 直接迁移之前已有的定义,会有完善的类型定义
    })
    
    export default userModule
    
    1. 使用 defineStore 定义 Store
    import { defineStore } from 'z-vuex-typed'
    import userModule fomr './modules/user'
    
    const { 
        store ,
        mapMutations,
        mapActions,
        mapGetters,
    } = defineStore({
        modules: {
            user: userModule
        },
        // ... 同样直接迁移之前已有的定义
        getters: {
            // ... 需要注意的是,为了让全局的 getters 拥有完备的类型定义,需要直接在这里写 getters
            //  而不能在外部定义后再引入
        }
    })
    
    // 正常导出 store
    export default store
    
    // 导出带类型的 maoX 函数
    export {
        mapMutations,
        mapActions,
        mapGetters,
    }
    
    
    1. 修改 vue 中 $store 的定义

    由于前面我们已经卸载了 vuex ,所以我们需要手动生命 $store 的类型。

    // src/shims-vuex.d.ts
    import Vue, { ComponentOptions } from 'vue'
    import store from '@/store'
    
    declare module 'vue/types/options' {
      interface ComponentOptions<V extends Vue> {
        store?: typeof store
      }
    }
    
    declare module 'vue/types/vue' {
      interface Vue {
        $store: typeof store
      }
    }
    
    
    1. 修改组件中 mapX 方法的引入方式
    <script>
    // improt { mapMutations, mapActions, mapGetters } from 'vuex'
    improt { mapMutations, mapActions, mapGetters } from '@/store'
    </script>
    

    尾巴

    已经 2023 年了,大家在创建新项目时相必一定不会再选择 vuex 了。但是如果不得不维护旧项目,又想要获得更好的开发体验,大家可以尝试一下这个项目,如果大家对这个项目有兴趣,欢迎根据前面的教程对项目进行改造。

    如果你发现任何 bug ,欢迎给我提 issue 。

    3 条回复    2023-08-21 09:10:44 +08:00
    amlee
        1
    amlee  
       2023-08-19 22:33:18 +08:00
    图啥呢,旧项目直接叠屎不得了
    justBugCoder
        2
    justBugCoder  
       2023-08-21 08:53:32 +08:00
    vue2 钉子户在此
    zcf0508
        3
    zcf0508  
    OP
       2023-08-21 09:10:44 +08:00 via Android
    @justBugCoder 升级到 2.7 ,打开 checkjs ,打开 volar 自动补充 defineComponent ,用我的这个项目更换 vuex ,你会获得更完美的开发体验
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1178 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 18:20 · PVG 02:20 · LAX 10:20 · JFK 13:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.