如今 vue3 已经接近尾声,各方面也得到了完善,对ts的支持也更强了。可是 vuex4 对 ts 的支持却没有任何改变,使用 useStore 的类型仍然为 any,在此官方提供了解决方案。
InjectionKey 注入类型
- 定义类型InjectionKey。
- InjectionKey在将商店安装到Vue应用程序时提供类型。
- 将类型传递InjectionKey给useStore方法。
// store.ts
import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'
// 手动声明 state 类型
export interface State {
count: number
}
// 定义注入类型
export const key: InjectionKey<Store<State>> = Symbol()
export const store = createStore<State>({
state: {
count: 0
}
})
接下来,安装到Vue应用程序时传递定义的注入类型:
// main.ts
import { createApp } from 'vue'
import { store, key } from './store'
const app = createApp({ ... })
// pass the injection key
app.use(store, key)
app.mount('#app')
最后,您可以将密匙传递给useStore方法以检索类型化的存储。
// in a vue component
import { useStore } from 'vuex'
import { key } from './store'
export default {
setup () {
const store = useStore(key)
store.state.count // typed as number
}
}
使用 declare module 覆盖 useStore 类型
可以看见,通过定义一个特殊的密匙,useStore就可以根据这个密匙查找对应储存的类型,并返回正确的类型,但这有个比较麻烦的一点,就是必须得手动定义 State 的类型,也就是说当写state的时候,还要在写多一份 state 接口,而且官方实例忽略了 modules 中 state 的类型,这里在下有个更好的方式解决这两个问题
- 根据当前 store 改造 useStore 类型
- 使用提供的类型数据改造 modules 文件的类型
- 使用 declare module ""vuex/types" 覆盖传入泛型
// store.ts
import { createStore } from 'vuex'
const store = createStore({
state: {
count: 1
},
mutations: {},
getters: {},
actions: {},
});
// 这里可以得到当前 store.state 的类型
type StoreStateType = typeof store.state
// modules/common.ts
// 改造一个泛型函数, 只用于在当前储存中保持类型正确
import { StoreOptions, Store } from "vuex";
const createModule = <S>(store: StoreOptions<S>) => store as Store<S>;
// 定义一个 module
export default createModule({
state: {
commonCount: 12
}
});
在让我们回到 store.ts 中,利用 declare module 覆盖 useStore 的类型
// store.ts
import { createStore } from "vuex";
import common from "./modules/common";
const store = createStore({
state: {
count: 1
},
mutations: {},
getters: {},
actions: {},
modules: {
common
}
});
// 覆盖原有 useStore 函数中, 泛型默认值类型
declare module "vuex" {
type StoreStateType = typeof store.state;
type ModulesType = {
common: typeof common.state;
}
export function useStore<S = StoreStateType & ModulesType>(): Store<S>;
}
export default store;
到了这一步就已经完成的对当前 state和 module 的 state 类型推测了,至于 dispatch,commit 中的魔法字符串还有 any getters,我还没有找到有效的解决方法,官方类型中定的比较固定,很难暴露出actions|getters|mutations中的 key 值类型,就很难顾及到当中的类型,又让dispatch,commit不在是任意的字符串,请教一下各位有好的解决方案吗?