Vue + TypeScript 嘗鮮體驗

ognm2924 8年前發布 | 32K 次閱讀 Vue.js TypeScript

  • 適用 Vue.version < 2.5 && Vue.version >= 2.2

其實我個人一開始很討厭 TypeScript 這個東西,就是因為討厭 Java 的啰里巴嗦,突然在我眼前出現了 JavaScript,便愛上了這門語言。

但現在的我稍稍又覺得這樣的東西其實還行,只使用類型系統也并沒有完全限制 JavaScript 本身的靈活性,并且他幫助我不會犯一些低級錯誤,而且還能配合 Visual Studio Code 的提示,我覺得這個還是很不錯的,最近忙起來的時候,甚至經常把兩個輸入框的 value 直接進行比較了,于是就想嘗試一下 TypeScript。

官方做法

Vue 2.2 以上之后,官方給 Vue已經添加了很多類型聲明,那么我們就來實踐一下在單文件 Vue 中使用 TypeScript。

1. webpack rules 中添加 ts-loader 相關(這里使用 webpack 2)

{
  test: /\.ts$/,
  exclude: /node_modules|vue\/src/,
  loader: 'ts-loader',
  options: {
    appendTsSuffixTo: [/\.vue$/]
  }
}

表示對 .ts 文件編譯時使用 ts-loader 進行讀取,appendTsSuffixTo 是為了讓 tsc 對 vue 文件能夠當成一個 module 進行處理,以解決 moudle not found 的問題(tsc 本身不認識 vue 結尾的文件)

2. 添加 .d.ts文件

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

也是為了讓 vscode 在 ts 文件中識別 vue 結尾文件

3. 項目根目錄下添加 tsconfig.json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "lib": [
      "dom",
      "es5",
      "es2015.promise"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "isolatedModules": false,
    "target": "es5"
  },
  "include": [
    "./src/**/*.ts"
  ]
}

allowSyntheticDefaultImports 是為了能夠用 es6 形式的 import,其他就參照 Vue 官網的弄了個最小化的 json。

4. 萬事俱備,讓我們 npm run dev 跑起來!

在這里,我們假設使用 Vue 官方的 webpack boilerplate,對 Hello.vue 進行一下改造。

在模板的 msg 下新增一行

<h2>Say Hello Times: {{ count }}</h2>

并將 script 部分修改成

<script lang="ts">
  import Vue, { ComponentOptions } from 'vue'
  // Declare the component's type
  interface HelloInterface extends Vue {
    msg: string,
    count: number,
    sayHello(): number
  }

  export {
    HelloInterface as interface
  }
  export default {
    data() {
      return {
        msg: 'Welcome to Your Vue.js App',
        count: 0
      }
    },
    methods: {
      sayHello() {
        this.count++;
        return this.count;
      }
    }
    // We need to explicitly annotate the exported options object
    // with the Hello type
  } as ComponentOptions<HelloInterface>;
</script>

這段代碼沒有什么太大的問題

接著我們改造一下 App.vue

<img src="./assets/logo.png" @click="sayHello">

 

<script lang="ts">
  import Vue, { ComponentOptions } from 'vue';
  import { interface as helloInterface, default as Hello } from './components/Hello.vue';
  interface App extends Vue {
    $refs: {
      // 對 helloComponent 進行聲明,可以使用 helloComponent 上的方法和屬性
      helloComponent: helloInterface
    }
  }
  export default {
    methods: {
      sayHello() {
        this.$refs.helloComponent.count++;
        this.$refs.helloComponent.sayHello();
      }
    },
    components: {
      Hello
    }
  } as ComponentOptions<App>;
</script>

也就是說,像 refs 這種動態的在運行時才能確定的東西,如果需要在 coding 過程中靜態化,則需要在 interface 中對其進行聲明,寫的 code 稍微有點多,不過可以接受。

  • 注: App.vue 修改成 lang=ts 后,頂層的 main.js 需要換成 main.ts 并修改 webpack 入口點,否則發生 file not found 錯誤

vue-class-component

官方的另一種推薦做法是 vue-class-component,不過 demo 和 readme 有點小問題,可把我這個 TypeScript 新手給難到啦,提了 pr 希望快快通過。

讓我們看看使用 vue-class-component 之后的 Hello.vue

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

  @Component
  export default class Hello extends Vue {
    msg: string = 'Welcome to Your Vue.js App'
    count: number = 0
    sayHello(): number {
      this.count++;
      return this.count;
    }
  }
</script>

再讓我們看看 App.vue

<script lang="ts">
  import Vue from 'vue'
  import Component from 'vue-class-component'
  import Hello from './components/Hello.vue';

  @Component({
    components: {
      Hello
    }
  })
  export default class App extends Vue {
    $refs: {
      helloComponent: Hello
    }

    sayHello() {
      this.$refs.helloComponent.count++;
      this.$refs.helloComponent.sayHello();
    }
  }
</script>

非常 Cool,非常精煉,暫時沒有想到可能會發生的沒法解決的因為 vue 或者 vue 組件 和 TypeScript 水土不服的編譯錯誤,而且都有了類型和提示。

總結

尤大佬說在接下來的 Vue 2.5 還會加強一系列的 TypeScript 支持( 鏈接 ),不知道是怎樣的支持呢。

另外,歡迎大家在評論區發表 Vue + TypeScript 的使用場景以及你遇到的錯誤。

 

來自:https://zhuanlan.zhihu.com/p/29971290

 

 本文由用戶 ognm2924 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!