什么是vuex
vuex 是 vue 中用来做状态管理的一个仓库,一般较大型的项目中有都会有它的影子。Vuex 主要包括state、mutations、actions、getters、modules 五个核心概念,有关具体的使用,本文不做重点讲解,下面将主要讲解如何在 vuex 中集成 typescript,做到代码提示功能。
最终效果预览
最终效果:
-
拿到 getters: 自动提示每个模块中定义的 getters,不用再回到定义的地方确认每一个 getters 的命名是否正确了
-
调用 mutation:
-
调用 actions
最终的效果就是,在我们输入引号的时候,编辑器会自动弹出提示,我们可以快速找到目标方法或者 getters 了,减少了代码出错的可能性。
实现步骤
- 创建项目,选用 vue-ts 开发模版
npm init vite@latest
- 引用 vuex
npm install vuex@next --save
- 在 src 下新建 store 目录,然后 store 下新建 index.ts
// store.ts
import { InjectionKey } from 'vue'
import { createStore, useStore as baseUseStore, Store } from 'vuex'
// 引入tab模块
import tabs, { TabsState } from './modules/tabs'
// 引入menu模块
import menu, { MenuState } from './modules/menu'
// 引入vuex-ts自定义类型推断类,代码提示的核心
import { CommonStore } from './vuex_ts'
// 定义根级State类型
export type RootState = {
tabs: TabsState,
menu: MenuState
}
// 把多个模块聚合在一起
export const modules = {
tabs: tabs,
menu: menu
}
export const key: InjectionKey<Store<RootState>> = Symbol()
export const store = createStore<RootState>({
modules
}) as CommonStore
// 定义自己的 `useStore` 组合式函数
export function useStore(): CommonStore {
return baseUseStore(key);
}
- 在 store 文件夹下,新建 modules 文件夹,并新建两个 ts 文件,这里每个ts文件相当于一个 vuex 模块,分别是:tabs.ts、menu.ts
// menu.ts
import {RootState} from '@/store'
import { ActionContext } from 'vuex';
// 定义menu模块下的,state的类型
export type MenuState = {
count:number;
}
// 定义menu模块下的state
export const state: MenuState = {
count:0
}
// 定义menu模块下的mutations
export const mutations = {
setCount(state:MenuState, count:number):void{
state.count = count
}
}
// 定义menu模块下的actions
export const actions = {
setAsyncCount({commit}:ActionContext<MenuState,RootState>){
setTimeout(() => {
state.count++
}, 1000);
}
}
// 定义menu模块下的getters
export const getters = {
getCount(state:MenuState){
return state.count
}
}
export default {
namespaced:true, // 声明命名空间
state,
mutations,
actions,
getters
}
// tabs.ts
import { ActionContext } from "vuex"
import { RootState } from "@/store"
// 定义单个tab的类型
interface ITab{
title:string,
path:string
}
// 定义tabs模块下的,state的类型
export type TabsState = {
tabLists: Array<ITab>
}
// 定义tabs模块下的state
export const state: TabsState = {
tabLists:[],
}
// 定义tabs模块下的mutations
export const mutations = {
addTab(state:TabsState, tab: ITab):void{
if(state.tabLists.some(item => item.path === tab.path)){return}
state.tabLists.push(tab);
}
}
// 定义tabs模块下的actions
export const actions = {
addAsyncTabs({commit}:ActionContext<TabsState,RootState>,tab:ITab){
if(state.tabLists.some(item => item.path === tab.path)){return}
state.tabLists.push(tab);
}
}
// 定义tabs模块下的getters
export const getters = {
getTabs(state:TabsState){
return state.tabLists
}
}
export default {
namespaced:true, // 声明命名空间
state,
mutations,
actions,
getters
}
- 在store文件夹下,新建vuex_ts.ts文件
// vuex_ts.ts
import {modules,RootState} from './index'
import { CommitOptions, DispatchOptions, Store as VuexStore } from 'vuex'
// 获取modules的类型
type Modules = typeof modules
// 获取所有模块下的mutations
type GetMutation<T> = T extends {mutations:infer G} ? G : never;
type GetMutations<T> = {
[K in keyof T]:GetMutation<T[K]>
}
type mutationsObj = GetMutations<Modules>
// 获取所有模块下的actions
type GetAction<T> = T extends {actions:infer G} ? G : never;
type GetActions<T> = {
[K in keyof T]:GetAction<T[K]>
}
type actionsObj = GetActions<Modules>
// 获取所有模块下的getters
type GetGetter<T> = T extends {getters:infer G} ? G : never;
type GetGetters<T> = {
[K in keyof T]:GetGetter<T[K]>
}
type getterObj = GetGetters<Modules>
// tabs/addTabs menu/setCount
type AddPrefix<prefix,keys> = `${prefix & string}/${keys & string}`
type GetKey<T,K> = AddPrefix<K,keyof T>;
type Getkeys<T> = {
[K in keyof T]:GetKey<T[K],K>
}[keyof T];
type ss = Getkeys<mutationsObj>
// 获取当前模块下每个函数的返回值
type GetFunc<T,A,B> = T[A & keyof T][B & keyof T[A & keyof T]]
type GetMethod<T> = {
[K in Getkeys<T>]:K extends `${infer A}/${infer B}` ? GetFunc<T,A,B> : unknown
}
type GetMutationsFunc = GetMethod<mutationsObj>
type GetActionsFunc = GetMethod<actionsObj>
type GetGettersFunc = GetMethod<getterObj>
// 去掉之前的,使用自己定义的
export type CommonStore = Omit<VuexStore<RootState>, 'commit' | 'getters' | 'dispatch'> & {
commit<K extends keyof GetMutationsFunc, P extends Parameters<GetMutationsFunc[K]>[1]>(
key: K,
payload?: P,
options?: CommitOptions
): ReturnType<GetMutationsFunc[K]>
} & {
getters: {
[K in keyof GetGettersFunc]: ReturnType<GetGettersFunc[K]>
}
} & {
dispatch<K extends keyof GetActionsFunc>(
key: K,
payload?: Parameters<GetActionsFunc[K]>[1],
options?: DispatchOptions
): ReturnType<GetActionsFunc[K]>
}
到这里,vuex集成ts,生成代码提示就已经实现了,这里看下效果: