Vue2.5+ Typescript 引入全面指南

Vue2.5+ Typescript 引入全面指南

系列目錄:css

寫在前面

寫這篇文章時的我,Vue使用經驗三個多月,Typescript徹底空白,
花了大概三個晚上把手頭項目遷移至Typescript,所以這篇文章更像個入門指引。vue

總原則

兩大原則:node

最小依賴引入

因爲我我的從Javascript到Typescript的升級,更傾向於平滑順移,所以,我對新依賴的引入總體保持克制原則,只引入了必要項,以儘可能貼近原生vue寫法:webpack

  • typescript
  • ts-loader

如下依賴均未引入:git

  • vue-class-component:官方維護,學習成本小,但與vuex融合性較差,計劃等官方完善對vuex支持後再考慮引入
  • vue-property-decorator:非官方維護,必定學習成本
  • vuex-class:非官方維護,在 vue-class-component 基礎上補充必定vuex支持(支持有限)
  • vuex-ts-decorators/vuex-typescript等:非官方維護,學習成本極高
PS: 後總結,vue官方維護的 vue-class-component 仍是頗有必要引入的,文末有詳細說明。

PS: tslint-loader因爲對vue的支持尚不完美,做爲可選項文末有詳細說明。github

既然用了 Typescript,不到萬不得已不用 any!

any 任意類型的存在,在我看來就是個潘多拉魔盒,一旦開啓,很容易養成偷懶的習慣,碰到難題就上 any。所以,個人建議是,儘可能不要去碰它,除非你無路可走。web

Vue-cli 生成項目啓用 Typescript

注:這裏只介紹Webpack模板下使用。

vue init webpack <項目名稱> 生成的項目需作以下改動以兼容 Typescript:vuex

依賴安裝

npm i --save-dev typescript ts-loader 安裝必要依賴。推薦使用 npm 8及以上版本。typescript

Webpack 配置

./build/webpack.base.conf.js,做以下改動:npm

  • entry入口文件main.js改成main.ts
entry: {
  app: './src/main.ts'
}
  • resolve.extensions添加.ts
resolve: {
  extensions: ['.js', '.ts', '.vue', '.json']
}
  • module.rules添加.ts解析規則:
module: {
  rules: [
    {
      test: /\.tsx?$/,
      loader: 'ts-loader',
      exclude: /node_modules/,
      options: {
        appendTsSuffixTo: [/\.vue$/]
      }
    }
  ]
}

tsconfig.json

項目根路徑下添加文件tsconfig.json,官方推薦配置以下:

// tsconfig.json
{
  "compilerOptions": {
    // 與 Vue 的瀏覽器支持保持一致
    "target": "es5",
    // 這能夠對 `this` 上的數據屬性進行更嚴格的推斷
    "strict": true,
    // 若是使用 webpack 2+ 或 rollup,能夠利用 tree-shake:
    "module": "es2015",
    "moduleResolution": "node"
  }
}

vue-shim.d.ts

src目錄下添加文件vue-shim.d.ts

declare module "*.vue" {
  import Vue from "vue";
  export default Vue;
}

意思是告訴TypeScript *.vue後綴的文件能夠交給vue模塊來處理。

.js 文件重命名爲 .ts 文件

src/main.js開始,包括src/router/index.js等逐一從.js重命名爲.ts

注意:重命名後對 vue文件的 import,需添加 .vue後綴

由於Typescript默認只識別*.ts文件,不識別*.vue文件

以前:

import App from './App'
import HelloWorld from '@/components/HelloWorld'

需改成:

import App from './App.vue'
import HelloWorld from '@/components/HelloWorld.vue'

.vue 文件改造

要點:

  • <script>標籤添加lang="ts"聲明
  • 使用Vue.extend定義組件

示例:

// src/components/HelloWorld.vue
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
})
</script>

npm run dev

至此運行項目,便可正常運行,vue對typescript的初步引入,基本完成。

TSLint

2017-12-6更新:
當前(2017年12月),對.vue文件,VSCode編輯器的編輯時提示,有了一個非官方方案(官方進度見如下issue,仍均未解決),TSLint Vue

簡單講,一給力小哥 Fork 了 VSCode 官方的 TSLint插件,添加了對 Vue 文件的支持。小哥更新蠻頻繁的,基本上第一時間跟隨官方插件的最新版,親測可用。

使用方式:VSCode Plugin,關閉 TSLint,下載並啓用 TSLint Vue便可:
TSLint Vue Plugin


當前(2017年11月),對.vue文件,能夠在關閉no-consecutive-blank-lines檢查前提下,開啓構建時TSLint支持;至於VSCode編輯器的編輯時提示,徹底沒有。

詳見TSLint的 issue 及vetur的 issue

不幸的是,也不能拿ESLint將就用,否則一堆以下的Error等着你:
Typescript ESLint Errors

因此,只剩倆選擇,要麼關了,要麼按照下面的配置將就着用:

  • 添加依賴
npm i --save-dev tslint tslint-loader tslint-config-standard
  • module.rules移除eslint-loader,添加tslint-loader預處理
// ./build/webpack.base.conf.js
module: {
  rules: [
    // {
    //   test: /\.(js|vue)$/,
    //   enforce: 'pre',
    //   exclude: /node_modules/,
    //   use: {
    //     loader: 'eslint-loader',
    //     options: {
    //       formatter: require('eslint-friendly-formatter')
    //     }
    //   }
    // },
    {
      test: /\.ts$/,
      exclude: /node_modules/,
      enforce: 'pre',
      loader: 'tslint-loader'
    },
    {
      test: /\.vue$/,
      loader: 'vue-loader',
      options: vueLoaderConfig
    },
  ]
}
  • vue-loader中開啓tslint-loader選項:
// ./build/vue-loader.conf.js

const merge = require('webpack-merge')

module.exports = {
  loaders: merge(utils.cssLoaders({
      sourceMap: isProduction
        ? config.build.productionSourceMap
        : config.dev.cssSourceMap,
      extract: isProduction
    }), {
      ts: ['ts-loader', 'tslint-loader']
    }
  ),
  ... // 其餘內容
}
  • 項目根路徑下添加文件tslint.json
// tslint.json
{
  "extends": "tslint-config-standard",
  "globals": {
    "require": true
  },
  "rules": {
    "no-consecutive-blank-lines": false
  }
}

no-consecutive-blank-lines 關閉的解釋 見這裏

簡單翻譯,vue-loadertslint-loader結合使用,就像是把.vue文件裏的<template><style>等非js內容所有置爲了空行同樣,爲此,只能關閉此檢查。

從新運行npm run dev,便可看到構建時可能輸出的tslint警告(tslint默認級別warning,不阻斷構建,如需error級別,可自行修改)
Typescript TSLint Warning

vue-class-component 的必要性

原生vue組件寫法會致使一很煩的問題:

data()若是以下形式定義數組,將會被推導爲[]never類型:

export default Vue.extend({
  data () {
    return {
      list: []  // type: []never
    }
  }
})

這樣一來,此array直接廢掉,由於不能往上附加值,只能如此提早聲明:

export default Vue.extend({
  data () {
    const list: string[] = []
    return {
      list: list
    }
  }
})

而引入vue-class-component後的class寫法,則能夠一行搞定:

<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class HelloWorld extends Vue {
  list: string[] = []

  hello () {
    list.push('Hello world')
  }
}
</script>

我我的是考慮到 vue-class-componentvuexmapState, mapGetters 等函數支持較差,(能夠藉助vuex-class引用),再加Decorators並非我對typescript的核心需求(Interface纔是!),決定的暫緩引入,先不增長複雜度。

Vuex

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

完整代碼

見 Github 庫:vue-vuex-typescript-demomaster 分支爲整合 vuex 示例,basic 分支爲不含 vuex 的基礎示例。

相關文章
相關標籤/搜索