在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
前言:关于Vue2.x 的TS改造,其实没有啥好说的。 对于vue-cli项目来说,从新跑一遍 vue create xxx-project ,选择Manually select features ,重新选择上typescript 选项即可。或者直接vue add typescript也可。 网上太多的资料,这里也推荐一些我觉得还可的(我是自己搞的,个人感觉不难吧,哈哈)
对于webpack,就是增加一下ts-loader,然后增加tsconfig.json,配置ts属性,再在eslint增加 ts代码规范。然后就去把老的项目文件改为ts文件,就好了。就这么一句话而已^_^,毕竟如今都2021了(毕竟TS已经流行多年了),教程实在太多了。 项目配置注意事项:本篇讲的是需要的一些注意事项,以及一些实现方式的异同,以及本人的观点(不妥之前请留言,多谢) WebPack配置修改
TypeScript配置文件项目根目录创建tsconfig.json文件,需要注意下面几个配置:
其他的,按照官方的来就可。 想noImplicitAny 就是比较鸡贼的玩法,但是你一个老项目的改造,可以边改变调整。不然,改着改着,就会失去重构信心。 eslint解析规则增加TS配置项根目录下,.eslintrc.js,参考配置 extends: [ 'plugin:vue/recommended', 'eslint:recommended', '@vue/typescript/recommended', '@vue/prettier', '@vue/prettier/@typescript-eslint' ], parserOptions: { ecmaVersion: 2020, }, 其实这个配置,看大家随意。默认vue-cli 生成的文件就好,没有vue-cli生成一个demo项目,copy一份。我们当然得遵从鹅厂的内部代码规范,就不贴了。 TypeScript的声明文件官方文档:https://www.tslang.cn/docs/handbook/declaration-files/introduction.html import Vue, { VNode } from 'vue'; declare global { interface Window { // 全局变量 i18n: any; eCharts: any; } } declare module 'vue/types/vue' { interface Vue { $bus: Vue; $route: any; $router: any; CancelToken: any; $message: any; $confirm: any; } } declare global { namespace JSX { interface Element extends VNode {} interface ElementClass extends Vue {} interface IntrinsicElements { [elem: string]: any; } } } 项目改造到这里就基本结束了 TS一些注意事项这部分对于刚刚改造,需要提醒成员的事项 TS类型anyany,这个东西好用,但是,如果完全放开的话,相信我,带最最后可能基本都是any 但是项目改造初期,可以先用any 顶替,后面有有时间,在进一步细化。这个度量,其实不是很好衡量。对于新手,代码合并的时候,还是打回any。 可选属性vs null undefinednull 和 undefined 是 ts 中的基础类型,分别具有值 null 和 undefined,默认情况下它们是所有类型的子类型,即可以赋值给任意类型。
tsconfig.js 文件中设置 strictNullChecks 为 true 时,就不能将 null 和 undefined 赋值给除它们自身和 void 之外的任意类型了。 在这种严格检查的情况下,如果你确实在某个地方想要给一个其他类型的值设置初始值为空,然后再赋值,可以使用联合类型来实现。 let test: string | null = 'hi' null 和 undefined 是区别的string|undefined、string|null 和 string|undefined|null 是三种不同的类型。 如果设置了 "strictNullChecks": true,可选参数会被自动加上 |undefined let test?: string = 'hi' interface/class/abstract class/type
不算symbol,js中有6种基本类型,number,string,boolean,null, undefined, object。但是只依靠这几种类型,来描述某个函数需要传什么样的参数,是远远不够的,这也是interface的使命--描述一个值(value)的形状(type)。 class首先也具有interface的能力,描述一个形状,或者说代表一种类型。此外class还提供了实现,也就是说可以被实例化; interface可以extends class,此时的class承担类型的角色。这里对于之前写java的我来说,有点WTF。其实对于undefined 有自己的类型叫做 undefined,java程序员也表示懵逼。
这里不像讲太多,觉得typescript手册就非常详细:https://www.tslang.cn/docs/handbook/basic-types.html Vue升级方案对比vue2升级到TS改造方案有很多种。 传统方案:vue-property-decoratorvue2对ts的支持主要是通过vue class component。这里主要依赖装饰器。顺手安利下《从java注解漫谈到typescript装饰器——注解与装饰器》。 此外,可以拓展了解一下元编程。
具体用法算是比较详细吧:https://github.com/kaorun343/vue-property-decorator <template> <div> <sidebar/> </div> </template> <script lang="ts"> import { Component, Vue, Watch } from 'vue-property-decorator'; import { Action, Mutation, State } from 'vuex-class'; import sidebar from 'layout/sidebar'; @Component({ components: { sidebar, }, }) export default class App extends Vue { private loading = true @State(state => state.user.theme) private readonly theme @Mutation('user/setThemeModel') private setThemeModel @Action('user/getUserInfo') private getUserInfo @Watch('$route.params.id') private handler() { // TODO } private get testCount() { // TODO } private mounted(): void { } } </script> 我个人不太喜欢这个风格,但是,但是周围都是这么样用,现在重构的项目就采用这个风格了 typescript mixin我对mixin不太感冒。既然要用,一定要注意以下几点: mixins合并规律:
mixins混合权重类似css权重规则(其实没有权重这个东西,但是结果是一样的,只是觉得这样好理解而已)
更多参看《vue mixins、Vue.extend() 、extends使用注意事项笔记》 用起来很简单 import { Component, Mixins, Vue } from 'vue-property-decorator'; // mixin @Component export default class PageLeave extends Vue { // TODO } // 组件 @Component({ components: { TitleBar, }, }) export default class CardPanel extends Mixins(PageLeave,OtherMixin) { //TODO } 不过TS的vue项目,mixin基本被我排除在外。
OPP本来就可以解决一切呀,不香么! vue-property-decorator方案缺点
个人更偏下一下方案。 tsx组合方案:Vue Components + TypeScript我起初是写react的,后写vue,所以更喜这种风格 import Vue, { VueConstructor, CreateElement, VNode } from 'vue'; interface InputInstance extends Vue { composing: boolean; } export default (Vue as VueConstructor<InputInstance>).extend({ name: 'demo-input', props: {}, data() {}, // TODO 更Vue其它组件一样 render(h: CreateElement): VNode { // TODO 逻辑 const classes = [] const wrapperAttrs = {...this.$attrs}; const wrapperEvents = {...this.$listeners}; // JSX 语法 return ( <div class={classes} {...{ attrs: wrapperAttrs, on: wrapperEvents }}> <input/> </div> ); } } 这里的mixin还是和之前的一样 // Count.mixin.ts import Vue from 'vue' import { mapGetters } from 'vuex' export default Vue.mixin({ computed: { ...mapGetters(['count']) }, methods: {} }) // Count.vue export default Vue.extend<{}, Methods, Computed, {}>({ mixins: [CountMixin], methods: {} }) 多个mixin混合import CountMixin, { Computed as CountComputed } from './Count.mixin' import LoadingMixin, { Computed as LoadingComputed } from './Loading.mixin' type Computed = CountComputed & LoadingComputed interface Methods { incrementCount: Function decrementCount: Function } export default Vue.extend<{}, Methods, Computed, {}>({ mixins: [CountMixin, LoadingMixin], methods: {} }) 但是,上面mixin的data 类型 糊了…… 推荐实现interface CountBindings extends Vue { count: number } export default (Vue as VueConstructor<CountBindings>).extend({ mixins: [CountMixin], methods: {} }) 具体可以参看,https://medium.com/glovo-engineering/vue-components-typescript-ff62db05829c composition-api这个首先需要npm i -S @vue/composition-api 然后全局注入 import VueCompositionApi from "@vue/composition-api"; Vue.use(VueCompositionApi); 其实,这个我也琢磨中。晚点在补充这方面的内容。 直接升级Vue3.0我是没有怎么做,如果是重写性重构,我肯定会直接用Vue3.0。但是对于庞大的项目,重构直接用3.0,还是怕怕。 虽然尤大大说vue2 与vue3,不会像angular2 与其后代版本差异那么大,但是,我还是缓缓先 Vuex Store的痛在ts里面使用vuex非常的蛋疼。 vuex ts版相关的vuex-class和vuex-module-decorators两个库应该是目前用的最多的(个人认为)。 https://www.npmtrends.com/vuex-aggregate-vs-vuex-class-vs-vuex-module-decorators
如果是老旧项目,个人推荐先使用vuex-class过度。
暂时先整理到这里,周末早点睡。后续再跟进……
转载本站文章《vue2.x老项目typescript改造过程经验总结》, |
请发表评论