Fork me on GitHub

使用 TypeScript 构建 Vue 项目

随着 TypeScript 的热度越来越高,Vue 官方提供的 TypeScript 支持也越来越多,Vue-CLI 3.0 更是直接提供了使用 TypeScript 来创建一个新工程的功能。

使用 Vue 进行开发也已经有半年的时间了,也非常怀念当时拿 TypeScript 写 Angular 的那种得心应手的舒畅,因此,在这个周末,花了一下午时间,将手头的一个 Vue 小 Demo 从 Js 修改成 Ts,打算看一下,Vue的 TypeScript 开发,到底靠谱不靠谱。

本篇博客,就来记录一下项目升级到 TypeScirpt 中的一些重点和遇到的坑吧。

项目搭建

新建项目

首先,我尝试将原有的 Vue 项目直接改动到 TypeScript,但发现改造起来是比较麻烦的,需要再去安装各种相关依赖,调整打包配置,修改组件的代码写法。

所以我决定直接新建一个 TypeScriptVue项目,然后将旧项目迁移过来。

Vue-CLI 3.0 中,提供了直接创建一个 TypeScript项目的功能。具体如下:

  1. 如果未安装Vue-CLI,直接使用下面命令安装

    1
    npm install -g @vue-cli
  2. 如果已安装,使用下面命令新建一个 Vue 项目,创建时选择手动选择特性(Manually select features)选项来添加Typescript支持。

    1
    vue create my-project-name

通过上面的命令,我们就创建了一个新的有TypeScript支持的 Vue项目。

迁移旧项目

当然,如果我们想将旧的Vue项目改造为新的项目的话,虽然比较麻烦,但也是可行的。需要以下几个步骤:

  1. npm 安装TypeScript

  2. npm安装 ts-loader,用于为webpack提供 .ts 文件的打包编译支持

  3. 修改webpackrules配置,添加关于打包.ts文件的配置。类似如下:

    1
    2
    3
    4
    5
    6
    7
    {
    test: /\.ts$/,
    loader: 'ts-loader',
    options: {
    appendTsSuffixTo: [/\.vue$/],
    }
    }

    同时修改extensions选项,添加.ts声明,使打包时可以识别.ts文件。

  4. 创建 Ts 的项目配置文件 tsconfig.json,需要注意的是,尽量打开配置的strict模式,才能保证Ts对类似this的类型检查。更多的配置项,例如支持JSX,生成sourceMap文件等选项,可以自行查看Typescript配置项文档

  5. 将项目打包入口文件main.js修改为main.ts

  6. 增加Vue文件的类型声明。因为Typescript是不支持Vue文件的,所以我们通过自定义的将Vue文件声明为一个模块,来保证Ts对其的正确处理。

    定义一个vue-shims.d.ts文件,放在项目任意位置,内容如下

    1
    2
    3
    4
    declare module '*.vue' {
    import Vue from 'vue'
    export default Vue
    }

通过以上几步,项目的Typescript配置就算完成了,通过将.vue文件的<script lang="js">标签修改为<script lang="ts">,就可以开始在项目中开始使用typescript了。

代码编写

vue-class-component

使用 Ts编写 Vue代码,Vue 官方提供了一个库 Vue-class-component,用于让我们使用Ts的类声明方式来编写vue组件代码。

这个库提供了一个@Component装饰器,基本使用方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import Vue from 'vue'
import Component from 'vue-class-component'

@Component({
props: {
propMessage: String
}
})
export default class App extends Vue {
// initial data
msg = 123

// use prop values for initial data
helloMsg = 'Hello, ' + this.propMessage

// lifecycle hook
mounted () {
this.greet()
}

// computed
get computedMsg () {
return 'computed ' + this.msg
}

// method
greet () {
alert('greeting: ' + this.msg)
}
}

我们以前书写组件的data数据项,可以直接声明为组件类的属性,methods,可以直接声明为类的方法,组件的各种生命周期函数,也可以直接作为类方法声明。而计算属性,更可以方便的通过类的getset函数来实现。

需要注意的是,因为Ts的模块系统只能自动识别.ts结尾的文件,因此我们在从.Vue文件导入组件类时,需要在导入路径上加上文件名后缀.vue

对于一些无法在Ts类中声明的方法和属性,例如watchprops我们可以直接在@Component装饰器中作为参数传入,或者使用下面这个库。

vue-property-decorator

这个库依赖于上面的vue-class-component,提供了更多的 Vue 组件相关方法的装饰器,可以让我们方便的在组件类中使用 Vue 实例提供的方法和属性,例如props, watch等。

vue-property-decorator提供了下面几个装饰器:

  • @Watch
  • @Prop
  • @Model
  • @Provide
  • @Inject
  • @Emit
  • @Mixins
  • @Component (依赖于vue-class-component)

通过这些装饰器,我们可以简单方便的使用Vue实例自身提供的一些方法和属性。如下:

1
2
3
4
5
6
7
8
9
10
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'

@Component
export default class YourComponent extends Vue {
@Prop(Number) propA!: number
@Prop({ default: 'default value' }) propB!: string

@Watch('child')
onChildChanged(val: string, oldVal: string) { }
}

具体这些装饰器的详细使用,可以前往vue-property-decorator项目主页 查看。

vuex-class

vuex-class 同样是基于vue-class-component的一个库,用于提供vuextypeScript支持。提供了以下几个装饰器:

  • @State
  • @Getter
  • @Action
  • Mutation

同时它还提供了一个namespace方法,用于获取vuex的某个命名空间。

vuex-class的具体细节,也可以前往其项目主页 查看。

有了上面提到的三个库,基本的开发应该就可以顺利的进行了。当然,因为VueTypeScript的支持还并不是非常完美,所以在使用的过程中可能还是会遇到一些坑,我这里说几个比较容易遇见的问题和解决办法。

使用装饰器时Ts 报错

这个问题,在tsconfig.js中设置experimentalDecorators 选项为true即可。

第三方库引入

我们在项目中会经常使用一些第三方的库,例如ElementUIecharts等等,当我们在Ts中引入这些库的时候,明明我们已经安装了,Ts仍然会报错找不到库路径。这是因为这些库中没有包含以.d.ts结尾的库声明文件,所以Ts就无法识别它们。

比较方便的解决办法是前往这个网站查看是否有对应第三方库的声明,如果有,直接使用npm安装即可。在这个网站,基本可以找到我们常用的所有库的声明type库。

当然,如果我们用的第三方库比较冷门的话,这个网站我们搜不到,我们也可以自己写一个声明文件放在项目中,并不是特别麻烦。

Vue全局方法和属性的使用

在写Vue的时候,我们通常会定义或使用第三方提供的全局方法,在TypeScript中照原来的方法使用的话,会报错Vue类型并不存在这个全局属性或方法。这是因为我们没有为Vue类型声明对应的属性和方法。

可以通过在上文提到的vue-shim.d.ts中添加对应的方法和属性声明,来避免这个报错。

例如elementUI提供的全局方法$message

1
2
3
4
5
declare module 'vue/types/vue' {
interface Vue {
$message: any,
}
}

属性也是一样,在Vueinterface中声明即可。

总结

总的来说,在Vue中使用TypeScript 目前是完全可行的,当然,还是远远比不上AngularTypeScript的那种非常契合丝滑的感受的。但也情有可原,毕竟vue框架的作者尤大大一年前还在知乎严肃的说Vue并不特别需要TypeScriptVue这个框架诞生之初也并没有想与Ts发生什么联系,就算现在想借助TypeScirpt来提高Vue在大型的长期项目中的开发效率,降低维护难度,也不是短期内就可以完成的事情。

但有理由相信,随着前端工程化程度的进一步深入,Vue也会加大与Typescript的结合力度,来进一步为我们提供更好的开发体验的。

另外,附上我使用 Vue-CLI搭建的Vue + TypeScirpt项目链接,有需要的同学可以参考一下。

项目传送门

谢谢阅读。

----本文结束感谢阅读----