关于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已经流行多年了),教程实在太多了。
本篇讲的是需要的一些注意事项,以及一些实现方式的异同,以及本人的观点(不妥之前请留言,多谢)
项目根目录创建tsconfig.json文件,需要注意下面几个配置:
其他的,按照官方的来就可。
想noImplicitAny 就是比较鸡贼的玩法,但是你一个老项目的改造,可以边改变调整。不然,改着改着,就会失去重构信心。
根目录下,.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一份。我们当然得遵从鹅厂的内部代码规范,就不贴了。
官方文档: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;?}
??}
}
项目改造到这里就基本结束了
这部分对于刚刚改造,需要提醒成员的事项
any,这个东西好用,但是,如果完全放开的话,相信我,带最最后可能基本都是any
但是项目改造初期,可以先用any 顶替,后面有有时间,在进一步细化。这个度量,其实不是很好衡量。对于新手,代码合并的时候,还是打回any。
null 和 ?developer/article/1839658/undefined 是 ts 中的基础类型,分别具有值 null 和 ?developer/article/1839658/undefined,默认情况下它们是所有类型的子类型,即可以赋值给任意类型。
null与?developer/article/1839658/undefined是所有其它类型的一个有效值。 这也意味着,你阻止不了将它们赋值给其它类型,就算是你想要阻止这种情况也不行。 null的发明者,Tony Hoare,称它为价值亿万美金的错误。
tsconfig.js 文件中设置 strictNullChecks 为 true 时,就不能将 null 和 ?developer/article/1839658/undefined 赋值给除它们自身和 void 之外的任意类型了。
在这种严格检查的情况下,如果你确实在某个地方想要给一个其他类型的值设置初始值为空,然后再赋值,可以使用联合类型来实现。
let test: string | null = 'hi'
string|?developer/article/1839658/undefined、string|null 和 string|?developer/article/1839658/undefined|null 是三种不同的类型。
如果设置了 "strictNullChecks": true,可选参数会被自动加上 |?developer/article/1839658/undefined
let test?: string = 'hi'
Declaration Type | Namespace | Type | Value |
---|---|---|---|
Namespace | X | X | |
Class | X | X | |
Enum | X | X | |
Interface | X | ||
Type Alias | X | ||
Function | X | ||
Variable | X |
不算symbol,js中有6种基本类型,number,string,boolean,null, ?developer/article/1839658/undefined, object。但是只依靠这几种类型,来描述某个函数需要传什么样的参数,是远远不够的,这也是interface的使命--描述一个值(value)的形状(type)。
class首先也具有interface的能力,描述一个形状,或者说代表一种类型。此外class还提供了实现,也就是说可以被实例化;
interface可以extends class,此时的class承担类型的角色。这里对于之前写java的我来说,有点WTF。其实对于?developer/article/1839658/undefined 有自己的类型叫做 ?developer/article/1839658/undefined,java程序员也表示懵逼。
TypeScript 通过采用结构化类型系统来体现 JavaScript 的动态特性,并且在类型推断方面做得非常出色,这意味着你不必像 C#或 Java 那样明确表达类型。 TypeScript 的设计目标之一不是为了创建一个“正确的类型系统”,而是“在正确性和生产力之间取得平衡”。——TypeScript 编译器不会强制你声明类型,类型安全的程度由你自己来决定。你甚至可以决定在项目的不同区域应用不同级别的类型安全严格程度。这种灵活性不是传统的静态类型语言可以提供的。
这里不像讲太多,觉得typescript手册就非常详细:https://www.tslang.cn/docs/handbook/basic-types.html
vue2升级到TS改造方案有很多种。
vue2对ts的支持主要是通过vue class component。这里主要依赖装饰器。顺手安利下《从java注解漫谈到typescript装饰器——注解与装饰器》。
此外,可以拓展了解一下元编程。
vue2比较令人诟病的地方还是对ts的支持,对ts支持不好是vue2不适合大型项目的一个重要原因。其根本原因是Vue依赖单个this上下文来公开属性,并且vue中的this比在普通的javascript更具魔力(如methods对象下的单个method中的this并不指向methods,而是指向vue实例)。换句话说,尤大大在设计Option API时并没有考虑对ts引用的支持)
具体用法算是比较详细吧: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>
我个人不太喜欢这个风格,但是,但是周围都是这么样用,现在重构的项目就采用这个风格了
我对mixin不太感冒。既然要用,一定要注意以下几点:
类似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基本被我排除在外。
早在2016年中期,丹·阿布拉莫夫(Dan Abramov)就写了《mixin被认为是有害的》(mixin Considered Harmful),他在书中辩称,将 mixin 用于在 React 组件中重用逻辑是一种反模式,主张远离它们。 他提到的关于 React mixins 的缺点同样适用于 Vue。
OPP本来就可以解决一切呀,不香么!
个人更偏下一下方案。
我起初是写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:?{}
})
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
这个首先需要npm i -S @vue/composition-api
然后全局注入
import?VueCompositionApi?from?"@vue/composition-api";
Vue.use(VueCompositionApi);
其实,这个我也琢磨中。晚点在补充这方面的内容。
我是没有怎么做,如果是重写性重构,我肯定会直接用Vue3.0。但是对于庞大的项目,重构直接用3.0,还是怕怕。
虽然尤大大说vue2 与vue3,不会像angular2 与其后代版本差异那么大,但是,我还是缓缓先
在ts里面使用vuex非常的蛋疼。
vuex ts版相关的vuex-class和vuex-module-decorators两个库应该是目前用的最多的(个人认为)。
https://www.npmtrends.com/vuex-aggregate-vs-vuex-class-vs-vuex-module-decorators
stars | issues | updated | created | |
---|---|---|---|---|
vuex-class | 1,653 | 18 | Oct 12, 2020 | Jan 14, 2017 |
vuex-module-decorators | 1,595 | 123 | May 8, 2021 | May 1, 2018 |
如果是老旧项目,个人推荐先使用vuex-class过度。
暂时先整理到这里,周末早点睡。后续再跟进……
转载本站文章《vue2.x老项目typescript改造过程经验总结》, 请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue/8637.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。