vue2.x老项目typescript改造过程经验总结
前言:
关于Vue2.x 的TS改造,其实没有啥好说的。
对于vue-cli项目来说,从新跑一遍 vue create xxx-project ,选择Manually select features ,重新选择上typescript 选项即可。或者直接vue add typescript也可。
网上太多的资料,这里也推荐一些我觉得还可的(我是自己搞的,个人感觉不难吧,哈哈)
https://www.tslang.cn/docs/handbook/migrating-from-javascript.html
https://blog.logrocket.com/vue-typescript-tutorial-examples/
https://github.com/ffxsam/vue-typescript-cookbook#initial-set-up
对于webpack,就是增加一下ts-loader,然后增加tsconfig.json,配置ts属性,再在eslint增加 ts代码规范。然后就去把老的项目文件改为ts文件,就好了。就这么一句话而已^_^,毕竟如今都2021了(毕竟TS已经流行多年了),教程实在太多了。
项目配置注意事项:
本篇讲的是需要的一些注意事项,以及一些实现方式的异同,以及本人的观点(不妥之前请留言,多谢)
WebPack配置修改
增加TS后缀:extensions: ['.js', '.vue', '.json', '.ts'],
增加ts-loader: {test: /\.ts$/, loader: 'ts-loader', exclude: /node_modules/, options: {appendTsSuffixTo: [/\.vue$/],}}
TypeScript配置文件
项目根目录创建tsconfig.json文件,需要注意下面几个配置:
"strictPropertyInitialization": false, // strict默认为true——必须要确保每个实例的属性都会初始值
"noImplicitAny": false, // false表示运行隐式的any类型,也就是允许不设置任何类型, 这个设置运行js文件直接改成ts文件
"allowJs": true, // 初期改造,肯定是JS与TS并行跑
"strictFunctionTypes": false, // 启用 vuex-class 需要开启此选项
"target": "es5", // 编译输出目标 ES 版本
"skipLibCheck": true,
"jsx": "preserve", // 在.tsx文件里支持JSX
"experimentalDecorators": true, // 启用装饰器
"strictNullChecks": true, // 当你声明一个变量时,它不会自动地包含null或undefined。
其他的,按照官方的来就可。
想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类型
any
any,这个东西好用,但是,如果完全放开的话,相信我,带最最后可能基本都是any
但是项目改造初期,可以先用any 顶替,后面有有时间,在进一步细化。这个度量,其实不是很好衡量。对于新手,代码合并的时候,还是打回any。
可选属性vs null undefined
null 和 undefined 是 ts 中的基础类型,分别具有值 null 和 undefined,默认情况下它们是所有类型的子类型,即可以赋值给任意类型。
null与undefined是所有其它类型的一个有效值。 这也意味着,你阻止不了将它们赋值给其它类型,就算是你想要阻止这种情况也不行。
null的发明者,Tony Hoare,称它为价值亿万美金的错误。
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
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, undefined, object。但是只依靠这几种类型,来描述某个函数需要传什么样的参数,是远远不够的,这也是interface的使命--描述一个值(value)的形状(type)。
class首先也具有interface的能力,描述一个形状,或者说代表一种类型。此外class还提供了实现,也就是说可以被实例化;
interface可以extends class,此时的class承担类型的角色。这里对于之前写java的我来说,有点WTF。其实对于undefined 有自己的类型叫做 undefined,java程序员也表示懵逼。
TypeScript 通过采用结构化类型系统来体现 JavaScript 的动态特性,并且在类型推断方面做得非常出色,这意味着你不必像 C#或 Java 那样明确表达类型。
TypeScript 的设计目标之一不是为了创建一个“正确的类型系统”,而是“在正确性和生产力之间取得平衡”。——TypeScript 编译器不会强制你声明类型,类型安全的程度由你自己来决定。你甚至可以决定在项目的不同区域应用不同级别的类型安全严格程度。这种灵活性不是传统的静态类型语言可以提供的。
这里不像讲太多,觉得typescript手册就非常详细:https://www.tslang.cn/docs/handbook/basic-types.html
Vue升级方案对比
vue2升级到TS改造方案有很多种。
传统方案:vue-property-decorator
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>
我个人不太喜欢这个风格,但是,但是周围都是这么样用,现在重构的项目就采用这个风格了
typescript mixin
我对mixin不太感冒。既然要用,一定要注意以下几点:
mixins合并规律:
覆盖的:data,props,methods,computed,inject
直接替换:el,template,propData
合并的:
methods,权重高的函数先执行
生命周期函数,watch监听回调函数,权重小的 先执行
mixins混合权重
类似css权重规则(其实没有权重这个东西,但是结果是一样的,只是觉得这样好理解而已)
*、全局 选项
1、......省略无数可能存在的嵌套 mixin
10、组件 - mixin - mixin
100、组件 - mixin
1000、组件选项
更多参看《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本来就可以解决一切呀,不香么!
vue-property-decorator方案缺点
vue class component与js的vue组件差异太大,另外需要引入额外的库,学习成本大幅度增高。
依赖于装饰器语法。而目前装饰器目前还处于stage2阶段(可查看tc39 decorators),在实现细节上还存在许多不确定性,这使其成为一个相当危险的基础。
复杂性增高。采用Vue Class Component且需要使用额外的库,相比于简单的js vue组件,显然复杂化。
个人更偏下一下方案。
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
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
vue2.x老项目typescript改造过程经验总结的更多相关文章
- 微信小程序豆瓣电影项目的改造过程经验分享
在学习微信小程序开发过程中,一部分的难点是前端逻辑的处理,也就是对前端JS的代码编辑:一部分的难点是前端界面的设计展示:本篇随笔基于一个豆瓣电影接口的小程序开源项目进行重新调整,把其中遇到的相关难点和 ...
- 使用 TypeScript 改造构建工具及测试用例
最近的一段时间一直在搞TypeScript,一个巨硬出品.赋予JavaScript语言静态类型和编译的语言. 第一个完全使用TypeScript重构的纯Node.js项目已经上线并稳定运行了. 第二个 ...
- 一个项目的SpringCloud微服务改造过程
SSO是公司一个已经存在了若干年的项目,后端采用SpringMVC.MyBatis,数据库使用MySQL,前端展示使用Freemark.今年,我们对该项目进行了一次革命性的改进,改造成SpringCl ...
- 拥抱下一代前端工具链-Vue老项目迁移Vite探索
作者:京东物流 邓道远 背景描述 随着项目的不断维护,代码越来越多,项目越来越大.调试代码的过程就变得极其痛苦,等待项目启动的时间也越来越长,尤其是需要处理紧急问题的时候,切换项目启动,等待的时间就会 ...
- 【iOS开展-94】xcode6如何使用GIT以及如何添加太老项目GIT特征?
(1)对于一个新项目:如何使用GIT?在新项目的过程,例如,您可以选择下面的复选框. (2)针对老项目,加入GIT功能. --在终端.cd到项目文件夹 --然后输入git init,初始化一个.git ...
- 使用typescript改造koa开发框架
强类型的 TypeScript 开发体验和维护项目上相比 JavaScript 有着明显的优势,那么对常用的脚手架进行改造也就势在必行了. 接下来开始对基于 koa 框架的 node 后端脚手架进行改 ...
- vue老项目升级vue-cli3.0
第一步我们卸载全局的vue2.0然后: 打开命令行 输入npm install -g @vue/cli-init 这个就是会安装全局的vue3.0版本.安装好之后我们也可以vue -V查看当前vu ...
- 新老单点的改造——-理解Cookie、Session、Token
近期参与了新老单点的改造,一直想总结一下,发现这篇文章比较贴切. 整理了如下: 随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,马上就面临一个问题,那就是要管理会话,必须记住哪些人登录 ...
- 「微前端实践」使用Vue+qiankun微前端方案重构老项目的本地验证
10月份换了新的工作,参与完一个月的需求迭代后,接到了项目重构的任务.简单来说,需要在短时间内提出方案设想,同时进行本地验证,最终需要拿出一套技术替换方案来.于是,埋头苦干了一个月,总算干了点成绩出来 ...
- vue2.0---vue-router总结(项目基于vue-cli)
vue2.0---vue-router总结(项目基于vue-cli) 1. 在项目中安装: npm install vue-router --save 2. 在项目中的引入: // The Vue b ...
随机推荐
- html5学习内容-5
(一)文字环绕排版 文字环绕图形 shape-outside属性 margin-box:外边距环绕 padding-box:内边距环绕 border-box:边框环绕 content-box:内容环绕 ...
- Net 高级调试之九:SOSEX 扩展命令介绍
一.介绍 今天是<Net 高级调试>的第九篇文章.这篇文章设计的内容挺多的,比如:扩展的断点支持,如何查找元数据,栈回溯,对象检查,死锁检测等等,内容挺多的.功能特别强大,使用特别方便,但 ...
- Java Junit单元测试(入门必看篇)
Hi i,m JinXiang 前言 本篇文章主要介绍单元测试工具Junit使用以及部分理论知识 欢迎点赞 收藏 留言评论 私信必回哟 博主收将持续更新学习记录获,友友们有任何问题可以在评论区留言 ...
- 使用 Proxychains 代理联网
前言 Proxychains 是 Linux 系统中一款简单好用的代理工具,可以指定特定命令走代理进行网络请求,适用于比较特殊的网络环境.最新版本为 proxychains4 安装 由于此软件存在于自 ...
- C++ LibCurl实现Web指纹识别
Web指纹识别是一种通过分析Web应用程序的特征和元数据,以确定应用程序所使用的技术栈和配置的技术.这项技术旨在识别Web服务器.Web应用框架.后端数据库.JavaScript库等组件的版本和配置信 ...
- offline RL | BCQ:学习 offline dataset 的 π(a|s),直接使用 (s, π(s)) 作为 Q learning 训练数据
题目: Off-Policy Deep Reinforcement Learning without Exploration,ICLR 2019 pdf 版本:https://arxiv.org/pd ...
- SPI扩展点在业务中的使用及原理分析
1 什么是SPI SPI 全称Service Provider Interface.面向接口编程中,我们会根据不同的业务抽象出不同的接口,然后根据不同的业务实现建立不同规则的类,因此一个接口会实现多个 ...
- three.js 汽车行驶效果
实现原理是使用TWEEN.Tween实现动画效果 实现 汽车模型加载 使用Promise编写模型的异步加载方法 Car.prototype.loadCar = function (position, ...
- 深度解读DBSCAN聚类算法:技术与实战全解析
探索DBSCAN算法的内涵与应用,本文详述其理论基础.关键参数.实战案例及最佳实践,揭示如何有效利用DBSCAN处理复杂数据集,突破传统聚类限制. 关注TechLead,分享AI全维度知识.作者拥有1 ...
- [ARC132E] Paw
题目链接 考虑最后形态,一定是有某一个区间 \([l,r]\) 保持初始的样子, \(l\) 前面都是 <,\(r\) 后面都是 >. 这个区间一定是某两个相邻圆点的位置.设 \(f_i\ ...