热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vuex对ts的支持太弱?想要获得vuex的智能提示?一个让vuex更好的支持typescript的解决方案

传统vuex编码让人觉得麻烦的一点就是state、getters、mutation、dispatch在调用时无法获得编辑器的智能提示,必须切换文件去查找。本以为用上typescri

传统 vuex 编码让人觉得麻烦的一点就是 state、getters、mutation、dispatch 在调用时无法获得编辑器的智能提示,必须切换文件去查找。本以为用上 typescript 后这个问题可以得到解决,却发现vuex官方提供的types并没有那么强大…

在找寻了一会儿各种解决方案后,觉得都存在这样或那样的问题(类型需要重复定义、侵入严重,和原本写法完全不一样),所以便自己写了这么一个解决方案,在获得了typescript的智能提示支持下却不需要重复写各种type和interface,和vuex原本写法保持一致,对业务代码侵入极小。

demo 项目由 vue-cli 3 生成,IDE 为 VSCODE

效果展示

1. state

《vuex对ts的支持太弱?想要获得vuex的智能提示?一个让 vuex 更好的支持 typescript 的解决方案》

《vuex对ts的支持太弱?想要获得vuex的智能提示?一个让 vuex 更好的支持 typescript 的解决方案》

state 会显示所有的 module、里面的属性及属性的类型

/src/store/modules/auth.ts

const moduleState = {
token: '',
tokenExpire: 0,
}

2. getters

getter 可以显示值类型

《vuex对ts的支持太弱?想要获得vuex的智能提示?一个让 vuex 更好的支持 typescript 的解决方案》

/src/store/modules/auth.ts

const moduleGetters = {
isLogin(state: State, getters: any, rootState: Store['state'], rootGetters: any) {
return !!state.token && (!!rootState.user.userId || !!rootState.user.accountId);
},
};

3. commit

《vuex对ts的支持太弱?想要获得vuex的智能提示?一个让 vuex 更好的支持 typescript 的解决方案》

《vuex对ts的支持太弱?想要获得vuex的智能提示?一个让 vuex 更好的支持 typescript 的解决方案》

commit 会显示所有注册的 mutation 以及对应 payload 的类型, 如果 payload 类型不对还会报错

《vuex对ts的支持太弱?想要获得vuex的智能提示?一个让 vuex 更好的支持 typescript 的解决方案》

/src/store/modules/auth.ts

const mutatiOns= {
setToken(state: State, payload: State['token']) {
state.token = payload || '';
},
setTokenExpire(state: State, payload: State['tokenExpire']) {
state.tokenExpire = payload || 0;
},
};

/src/store/modules/user.ts

const mutatiOns= {
setAccountId(state: State, payload: State['accountId']) {
state.accountId = payload || '';
},
setUserId(state: State, payload: State['userId']) {
state.userId = payload || '';
},
setUserInfo(state: State, payload: State['info']) {
state.info = payload || {};
},
};

/src/store/modules/pageCache.ts

const mutatiOns= {
setPageToCache(state: State, payload: any) {
state.pagesName.unshift(payload.pageName);
setTimeout(() => {
if (payload.callback) payload.callback();
}, 0);
},
resetPageCache(state: State) {
state.pagesName = [...cachePages];
},
};

4. dispatch

和 commit 类似

《vuex对ts的支持太弱?想要获得vuex的智能提示?一个让 vuex 更好的支持 typescript 的解决方案》

《vuex对ts的支持太弱?想要获得vuex的智能提示?一个让 vuex 更好的支持 typescript 的解决方案》

/src/store/modules/auth.ts

const actiOns= {
updateAuthData({ commit }: ActionContext, payload: any) {
commit('setToken', payload.token);
commit('setTokenExpire', payload.expire);
},
cleanAuthData({ commit }: ActionContext) {
commit('setToken', '');
commit('setTokenExpire', 0);
},
};

实现方式

上面可以看到,这个方案在保证了 vuex 原来的写法(稍微有一点点变化,从 this.$store 换为 this.\$$store)上支持了 typescript 的类型检查,为了实现它,vuex 的 store 在初始化的时候我们需要做一些额外的工作,但是也仅限于这一点额外的工作了,后续的 module(业务)的增加,也完全像 vuex 本来的写法那样去定义各种 state、getters、mutation、action,一劳永逸的获得 typescript 对 vuex 各种调用的支持。

1. 改造 vuex 部分

先来看看最基本的 vuex 代码

/store/modules/auth.ts

// ts 校验会提示好几个函数具有隐式 any 入参,暂略过
const moduleState = {
token: '',
tokenExpire: 0,
};
const moduleGetters = {
isLogin(state, getters, rootState, rootGetters) {
return !!state.token && (!!rootState.user.userId || !!rootState.user.accountId);
},
};
const mutatiOns= {
setToken(state, payload) {
state.token = payload || '';
},
setTokenExpire(state, payload) {
state.tokenExpire = payload || 0;
},
};
const actiOns= {
updateAuthData({ commit }, payload) {
commit('setToken', payload.token);
commit('setTokenExpire', payload.expire);
},
cleanAuthData({ commit }) {
commit('setToken', '');
commit('setTokenExpire', 0);
},
};
export default {
state: moduleState,
getters: moduleGetters,
mutations,
actions,
};

/store/index.ts

import Vue from 'vue';
import Vuex from 'vuex';
import auth from './modules/auth';
import user from './modules/user';
import pageCache from './modules/pageCache';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
auth,
user,
pageCache,
},
});
export default store;

下面我们给它加一点 Magic

/store/index.ts

import Vue from 'vue';
import Vuex from 'vuex';
import auth from './modules/auth';
import user from './modules/user';
import pageCache from './modules/pageCache';
Vue.use(Vuex);
// 从 module 的 state 中提取 state 的类型并集合
interface State {
auth: typeof auth.state;
user: typeof user.state;
pageCache: typeof pageCache.state;
}
// 将 getter 函数转换成 {getterName: getterFuncsReturnType} 的对象类型
export type ReturnGetters any }> = {
[P in keyof T]: ReturnType;
}
// 提取所有 module 的 getter 函数类型对象
type GettersFuncs = (
typeof auth.getters
& typeof user.getters
& typeof pageCache.getters
)
// 将 getter 转换成对象
type Getters = ReturnGetters
// 提取 mutation 函数类型
type CommitFuncs = (
typeof auth.mutations
& typeof user.mutations
& typeof pageCache.mutations
)
// 将 mutation 函数名及 payload 类型转换成 commit 函数的两个入参类型
interface Commit {
(type: T, payload?: Parameters[1]): void;
}
// dispatch 处理步骤同 commit
type DispatchFuncs = (
typeof auth.actions
& typeof user.actions
& typeof pageCache.actions
)
interface Dispatch {
(type: T, payload?: Parameters[1]): Promise;
}
const store = new Vuex.Store({
modules: {
auth,
user,
pageCache,
},
});
export default store;
// 其他 ts 文件解构导入时获得每个对象的改造后类型
export const { state } = store;
export const { getters }: { getters: Getters } = store; // 定义 getters 的类型
export const { commit }: { commit: Commit } = store; // 定义 commit 的类型
export const { dispatch }: { dispatch: Dispatch } = store; // 定义 commit 的类型
// 导出类型 Store 以便在 Vue 原型上定义类型
export interface Store {
state: State;
getters: Getters;
commit: Commit;
dispatch: Dispatch;
}

为了避免循环引用,我们需要在 /src/types/ 下面建一个 .d.ts 文件 ,来让各个 module 可以引用到全局的 State (rootState、commit、dispatch)

/src/types/store.d.ts

import { Store as s } from '../store/index';
export { ReturnGetters } from '../store/index';
export interface Store extends s {}
export interface ActionContext {
dispatch: Store['dispatch']; // 全局的 dispatch, 有 ts 提示支持
commit: Store['commit']; // 全局的 commit, 有 ts 提示支持
state: S;
getters: G;
rootState: Store['state']; // 全局的 state, 有 ts 提示支持
rootGetters: any; // 暂时还无法实现将全局 getter 定义过来,会出现类型循环引用问题
}

最后去修改我们的 module(仅举例auth)

/src/store/modules/auth.ts

import { ReturnGetters, Store, ActionContext } from '../../types/store';
const moduleState = {
token: '',
tokenExpire: 0,
};
type State = typeof moduleState; // 提取 state 类型
const moduleGetters = {
isLogin(state: State, getters: any, rootState: Store['state'], rootGetters: any) {
return !!state.token && (!!rootState.user.userId || !!rootState.user.accountId);
},
};
type Getters = ReturnGetters; // 提取 getter 类型
const mutatiOns= {
setToken(state: State, payload: State['token']) {
state.token = payload || '';
},
setTokenExpire(state: State, payload: State['tokenExpire']) {
state.tokenExpire = payload || 0;
},
};
const actiOns= {
updateAuthData({ commit }: ActionContext, payload: any) {
commit('setToken', payload.token);
commit('setTokenExpire', payload.expire);
},
cleanAuthData({ commit }: ActionContext) {
commit('setToken', '');
commit('setTokenExpire', 0);
},
};
export default {
state: moduleState,
getters: moduleGetters,
mutations,
actions,
};

2.改造 vue 实例化 vuex 部分

/src/main.ts

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store, { Store } from './store/index';
// 其他 ts 文件在直接解构引入的时候,也可以获得智能提示
// import { state, getters, commit, dispatch } from './store/index';
Vue.config.productiOnTip= false;
const app = new Vue({
router,
store,
render: h => h(App),
}).$mount('#app');
// 将改造过后的 Store 类型声明到 vue 的原型上,这样就可以在.vue 文件中获得 IDE 的智能提示了
// 因为下面去声明一个新的 Store 类型的时候,无法覆盖 vue 原有的 $store 类型声明,所以采取一个新的名字 $$store 来应用新的类型,本质上都是 app.$store
Vue.prototype.$$store = app.$store;
declare module 'vue/types/vue' {
interface Vue {
$$store: Store;
}
}

至此 vuex 的 typescript 支持改造就完成了(其中 /src/store/index.ts 完全可以用nodejs写个脚本读取所有module文件名然后用mustache根据模板来生成,每次新增模块时跑一行命令就更新了),之后就可以愉快的使用 vuex 原本的写法又不用来回切文件找各种命名了,并且写错的时候 ts 还会校验错误,妈妈再也不用担心我犯这种低级错误了~

ps: 这个方案可能还不够好(rootGetters 类型没有实现等…),欢迎各位交流学习

ppps: 下一步想将这些 ts 类型的代码抽离成一个工具库,但是初步想了一下有点难度,就先以 demo 的形式分享一下

demo

地址:github

代码拉下来以后

yarn install

之后就可以在 .vue 文件和 .ts 文件中体验 vuex 获得智能提示的便利了~

如果对你有帮助的话,麻烦给个star呗~

  • 作者:BarneyZhao
  • 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

推荐阅读
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 提升Python编程效率的十点建议
    本文介绍了提升Python编程效率的十点建议,包括不使用分号、选择合适的代码编辑器、遵循Python代码规范等。这些建议可以帮助开发者节省时间,提高编程效率。同时,还提供了相关参考链接供读者深入学习。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
author-avatar
b1b
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有