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 ...
随机推荐
- 如何避免JavaScript中的内存泄漏?
前言 过去,我们浏览静态网站时无须过多关注内存管理,因为加载新页面时,之前的页面信息会从内存中删除. 然而,随着单页Web应用(SPA)的兴起,应用程序消耗的内存越来越多,这不仅会降低浏览器性能,甚至 ...
- go语言reflection反射
一.反射 1.1简介 Reflection(反射)在计算机中就是表示程序在运行期间能够探知自身结构的能力类型(类型信息.内存结构.更新变量.以及调用方法) 1.2使用场景 函数的参数类型是interf ...
- [C++]P3379 LCA 最近公共祖先
最近公共祖先 LCA 倍增写法 LCA的倍增主要由三个重要的过程组成 预处理lg数组 DFS求fa depth 倍增节点 观看以下内容前建议先把完整代码大致纵览一遍,有利于理解各个函数的意义 倍增思想 ...
- JVM-JVM如何加载类
一.Java 语言的类型可以分为两大类: 基本类型(primitive types) 引用类型(reference types):类.接口.数组类和泛型参数(泛型参数会在编译中被擦除),因此Java虚 ...
- 产品代码都给你看了,可别再说不会DDD(十):CQRS
这是一个讲解DDD落地的文章系列,作者是<实现领域驱动设计>的译者滕云.本文章系列以一个真实的并已成功上线的软件项目--码如云(https://www.mryqr.com)为例,系统性地讲 ...
- 使用rancher rke快速安装k8s集群
概述 Rancher Kubernetes Engine(RKE)是一个用于部署.管理和运行Kubernetes集群的开源工具.旨在简化Kubernetes集群的部署和操作. RKE具有以下特点和功能 ...
- rancher安装及部署k8s
一.安装docker 参考:https://www.cnblogs.com/uestc2007/p/15598527.html 二.安装rancher 1.Rancher概述 rancher官方文档 ...
- c#中责任链模式详解
基本介绍: "责任链"顾名思义,是指一个需要负责处理请求的链条. 每个链条节点都是一个单独的责任者,由责任者自己决定是否处理请求或交给下一个节点. 在设计模式中的解释则 ...
- AntDesignBlazor示例——新建项目
本示例是AntDesign Blazor的入门示例,在学习的同时分享出来,以供新手参考. 1. 开发环境 VS2022 17.8.2 .NET8 AntDesign 0.16.2 2. 学习目标 创建 ...
- 功能不够,SQL来凑,修改数据库的正确姿势?
修改数据库是一项关键任务,需要小心谨慎地执行,以确保数据的完整性和准确性.下面是一个详细的步骤指南,介绍了正确修改数据库的姿势. 第一步:备份数据库 在进行任何数据库修改之前,务必备份数据库.这样,如 ...