在Vue項目中使用Typescript


3.0遲遲沒有發布release版本,現階段在vue項目中使用Typescript需要花不小的精力在工程的配置上面。主要的工作是webpack對TS,TSX的處理,以及2.x版本下面使用class的形式書寫vue 組件的一些限制和注意事項。

 

webpack 配置

配置webpack對TS,TSX的支持,以便於我們在Vue項目中使用Typescript和tsx。

module.exports = { entry: './index.vue', output: { filename: 'bundle.js' }, resolve: { extensions: ['.ts', '.tsx', '.vue', '.vuex'] }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { loaders: { ts: 'ts-loader', tsx: 'babel-loader!ts-loader', } } }, { test: /\.ts$/, loader: 'ts-loader', options: { appendTsSuffixTo: [/TS\.vue$/] } }, { test: /\.tsx$/, loader: 'babel-loader!ts-loader', options: { appendTsxSuffixTo: [/TSX\.vue$/] } } ] } }

在上面的配置中,vue文件中的TS內容將會使用ts-loader處理,而TSX內容將會按照ts-loader-->babel-loader的順序處理。

appendTsSuffixTo/appendTsxSuffixTo配置項的意思是說,從vue文件里面分離的script的ts,tsx(取決於<script lang="xxx"></script>)內容將會被加上ts或者tsx的后綴,然后交由ts-loader解析。

我在翻看了ts-loader上關於appendTsxSuffixTo的討論發現,ts-loader貌似對文件后綴名稱有很嚴格的限定,必須得是ts/tsx后綴,所以得在vue-loader extract <script>中內容后,給其加上ts/tsx的后綴名,這樣ts-loader才會去處理這部分的內容。

ts-loader只對tsx做語法類型檢查,真正的jsx-->render函數應該交由babel處理。

所以我們還需要使用plugin-transform-vue-jsx來將vue jsx轉換為真正的render函數。

// babel.config.json { "presets": ["env"], "plugins": ["transform-vue-jsx"] }

同時,配置TS對tsx的處理為preserve,讓其只對tsx做type類型檢查。

// tsconfig.json {   "compilerOptions": {     "jsx": "preserve", }

 

使用vue cli 4.x

高版本的vue cli如4.x已經集成了vue + typescript的配置。選擇use Typescript + Use class-style component syntax選項創建工程。

創建后的工程目錄如下:

在src根目錄下,有兩個shims.xx.d.ts的類型聲明文件。

// shims.vue.d.ts declare module "*.vue" {   import Vue from "vue";   export default Vue; }
// shims.jsx.d.ts import Vue, { VNode } from "vue"; declare global {   namespace JSX {     // tslint:disable no-empty-interface     interface Element extends VNode {}     // tslint:disable no-empty-interface     interface ElementClass extends Vue {}     interface IntrinsicElements {       [elem: string]: any;     }   } }

它們是作什么用的呢?

shims.vue.d.ts給所有.vue文件導出的模塊聲明了類型為Vue,它可以幫助IDE判斷.vue文件的類型。

shims.jsx.d.ts 為 JSX 語法的全局命名空間,這是因為基於值的元素會簡單的在它所在的作用域里按標識符查找。當在 tsconfig 內開啟了 jsx 語法支持后,其會自動識別對應的 .tsx 結尾的文件,(也就是Vue 單文件組件中<script lang="tsx"></script>的部分)可參考官網 tsx

 

基本用法

在vue 2.x中使用class的方式書寫vue組件需要依靠vue-property-decorator來對vue class做轉換。

<script lang="ts"> import { Component, Prop, Vue } from "vue-property-decorator"; export default class extends Vue {   @Prop({ default: 'default msg'}) private msg!: string;   name!: string;   show() {     console.log("this.name", this.name);   } } </script>

導出的class是經過Vue.extend之后的VueComponent函數(理論上class就是一個Function)。

其最后的結果就像我們使用Vue.extend來擴展一個Vue組件一樣。

// 創建構造器 var Profile = Vue.extend({   template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',   data: function () {     return {       firstName: 'Walter',       lastName: 'White',       alias: 'Heisenberg'     }   } }) export default { components: { Profile } }

注意上面的Profile組件並不是和我們平時一樣寫的Vue組件是一個plain object配置對象,它其實是一個VueComponent函數。

父組件實例化子組件的時候,會對傳入的vue object 進行擴展,使用Vux.extend轉換為組件函數。
如果components中的值本身是一個函數,就會省略這一步。這一點, 從Vue 源碼中可以看出。

if (isObject(Ctor)) {     Ctor = baseCtor.extend(Ctor) }

上面的Ctor就是在components中傳入的組件,對應於上面導出的Profile組件。

 

使用vuex

使用vuex-class中的裝飾器來對類的屬性做注解。


import Vue from 'vue'import Component from 'vue-class-component'import { State, Getter, Action, Mutation, namespace } from 'vuex-class' const someModule = namespace('path/to/module') @Component export class MyComp extends Vue { @State('foo') stateFoo @State(state => state.bar) stateBar @Getter('foo') getterFoo @Action('foo') actionFoo @Mutation('foo') mutationFoo @someModule.Getter('foo') moduleGetterFoo // If the argument is omitted, use the property name // for each state/getter/action/mutation type @State foo @Getter bar @Action baz @Mutation qux created () { this.stateFoo // -> store.state.foo this.stateBar // -> store.state.bar this.getterFoo // -> store.getters.foo this.actionFoo({ value: true }) // -> store.dispatch('foo', { value: true }) this.mutationFoo({ value: true }) // -> store.commit('foo', { value: true }) this.moduleGetterFoo // -> store.getters['path/to/module/foo'] } }

 

mixin

對於mixin,我們使用class的繼承很容易實現類似功能。

import Vue from 'vue' import { Component } from 'vue-property-decorator' @Component class DeployMixin extends Vue{   name: string;   deploy(){     // do something   } } @Component class Index extends DeployMixin{   constructor(){      super()   }   sure(){     this.deploy()   } }

廣州設計公司https://www.houdianzi.com 我的007辦公資源網站https://www.wode007.com

VS code jsx快捷鍵

設置 VS code中對emmet的支持

"emmet.includeLanguages": { "JavaScript": "html" }

或者是

"emmet.includeLanguages": { "JavaScript": "javascriptreact" }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM