在Vue中使用TypeScript

很早以前,想在Vue中使用TypeScript來增強開發體驗,TypeScript的優點自不必多說。查了很多資料,了解了當時在Vue中使用TypeScript的體驗。由於當時TypeScript對Vue支持不夠,無法推斷出vue實例中的this,遂擱置了這種想法。在Vue2.5及TypeScript2.4發布之後,TypeScript對Vue的支持加強,this的問題得到了解決,終於能在Vue中愉快的使用TypeScript。

如果想在React中使用TypeScript,可以藉助create-react-app-typescript腳手架工具,默認創建基於TypeScript的React應用,開發體驗也很棒。跟React不同,目前Vue的官方腳手架Vue-cli工具還沒有默認提供對TypeScript的支持,想了解更多的信息,可以看一下這個issue。

既然Vue-cli沒有提供默認的支持,那我們就自己來配置,相信對於一個合格的前端來說,配置開發環境是必備的技能......其實網上有很多相關的配置教程,那就簡單的過一下吧。

1 初始化vue-cli項目,安裝typescript,ts-loader,tslint,tslint-loader,tslint-config-standard,vue-property-decorator.上面只有typescript,ts-loader是必須的,其餘的包用於增強開發體驗。

2 增加tsconfig.json,下面是我的配置(值得注意的是,建議開啟嚴格模式,也就是下面的strit為true這個選項,這樣才能嚴格的推斷Vue中的property):

{n "include": [n "./src/**/*"n ],n "exclude": [n "node_modules"n ],n "compilerOptions": {n "allowSyntheticDefaultImports": true,n "experimentalDecorators": true,n "strict": true,n "allowJs": true,n "module": "es2015",n "target": "es5",n "moduleResolution": "node",n "isolatedModules": true,n "lib": [n "dom",n "es5",n "es2015.promise"n ],n "sourceMap": true,n "pretty": truen }n}n

2 在webpack.base.conf.js中需要配置對ts和tsx的支持(加了注釋的地方是新增的或需要修改的配置):

resolve: {n extensions: [.js, .vue, .json, ts, tsx], // 新增了ts, tsxn alias: {n vue$: vue/dist/vue.esm.js,n @: resolve(src),n }n },n module: {n rules: [n {n test: /.ts$/, // 用於載入項目中的ts文件n exclude: /node_modules/,n enforce: pre,n loader: tslint-loadern },n {n test: /.tsx?$/, // 用於載入項目中的tsx文件n loader: ts-loader,n exclude: /node_modules/,n options: {n appendTsSuffixTo: [/.vue$/],n }n }]n

3 將main.js重命名為main.ts, 並在webpack.base.conf.js中修改路徑名

entry: {n app: ./src/main.tsn }n

4 在src目錄下新增vue-shim.d.ts,增加對Vue的聲明:

declare module *.vue {n import Vue from vuen export default Vuen}n

經過上面的配置,基本的開發環境就搞定了,接下來就可以開始寫代碼。為了提升開發體驗,這裡使用了vue-property-decorator這個包,其主要特點是封裝了vue-class-component這個官方包,提供7個裝飾器,通過繼承Vue的方式來創建實例,大致是下面這樣的:

<script lang="ts">n import {Vue, Component, Prop, Emit, Watch} from vue-property-decorator;n import CommonModal from ./CommonModal.vue;nn @Component({n components: {n Foon }n })n export default class HelloWorld extends Vue{nn @Prop({n type: String,n required: truen })n childProp: string|number;nn tasks: Array<number|string> = [];nn task: string|number = ;nn addTask() {n this.tasks.push(this.task);n this.task = ;n }nn @Watch(task)n onTaskChange(oldValue: string|number, newValue: string|number) {n console.log(`oldValue ${oldValue}`);n console.log(`newValue ${newValue}`);n }nn @Emit(handleClick)n // 函數的參數值即是emit的payloadn emitTasks(tasks: Array<string|number>) {n this.tasks[0] = haha;n }n }n</script>n

從上面的例子可以大致看出新的開發方式。這裡需要注意的是,需要在script中加入lang=ts。因為使用了vue-property-decorator,所以在vue的實例中寫屬性的時候跟以前有些不同。首先,需要在Component這個裝飾器的參數中包含需要引用的組件;其次,使用emit的時候,像父組件傳遞的參數即是函數的參數,就像上面的tasks;父組件向子組件傳遞的屬性,需要使用Prop這個裝飾器進行聲明等等。

雖然目前TypeScript對Vue支持比較好,但是Vue中的狀態管理工具Vuex還不完善,所以我們可以使用vuex-class這個三方工具包來增強。其提供了State,Getter, Action,Mutation,nam-espace這幾個裝飾器,具體做法可以參考它的官方實例,代碼如下:

import Vue from vuenimport Component from vue-class-componentnimport {n State,n Getter,n Action,n Mutation,n namespacen} from vuex-classnnconst ModuleGetter = namespace(path/to/module, Getter)nn@Componentnexport class MyComp extends Vue {n @State(foo) stateFoon @State(state => state.bar) stateBarn @Getter(foo) getterFoon @Action(foo) actionFoon @Mutation(foo) mutationFoon @ModuleGetter(foo) moduleGetterFoonn // If the argument is omitted, use the property namen // for each state/getter/action/mutation typen @State foon @Getter barn @Action bazn @Mutation quxnn created () {n this.stateFoo // -> store.state.foon this.stateBar // -> store.state.barn this.getterFoo // -> store.getters.foon this.actionFoo({ value: true }) // -> store.dispatch(foo, { value: true })n this.mutationFoo({ value: true }) // -> store.commit(foo, { value: true })n this.moduleGetterFoo // -> store.getters[path/to/module/foo]n }n}n

有了Vuex-class的加持,Vue在狀態管理方面有了明顯的提升。下面會簡單的介紹一下在使用了TypeScript之後,如何來管理狀態。

我的做法是,為每一個後端API 介面創建一個TypeScript的interface,然後通過這個interface來定義Vuex中的state,就像這樣:

// stateType.jsnexport interface USERINFO {n userId: number;n userName: string;n avatar: stringn}nnexport default interface STATE {n userInfo: USERINFO;n}nn// state.jsnimport STATE from ./stateType.js;nnconst state: STATE = {n userInfo: {n userId: 0,n userName: ,n avatar: ,n }n};nnexport default state;n

這樣做的好處是,通過interface來檢查後台返回的數據結構是否滿足要求,同時也可以在前端使用數據渲染頁面的時候做一定的限制。當需要進行重構時,只需要修改state對應的interface,然後就能一路順暢的該下去,非常爽。

目前使用TypeScript重構的Vue項目已經正式上線,維護性大大提升,感覺好極了。

參考資源:

kaorun343/vue-property-decorator

ktsn/vuex-class

Vue2.5+ Typescript 引入全面指南 - Vuex篇

推薦閱讀:

vuejs的.vue文件中的style標籤中的css樣式,背景圖路徑不對?
技術圈爭論跑去告老闆會讓人不齒嗎?
vuejs 開發中, 有必要把button, input封裝成組件嘛?
使用vue.js怎麼寫出輪播圖?
如何使用vue.js構造modal(彈窗)組件?

TAG:Vuejs | TypeScript | Vuex |