vue + typescript 踩坑筆記(一)

MADAO是不會開花的發表於2019-02-25

最近在用 vue + typescript 寫一個專案,由於是第一次使用typescript,所以踩了一些坑,這裡記錄一下。

一. vue-property-decorator

使用vue-cli搭建專案的話,可以從它給出的Home.vue檔案中,可以看到用typescript寫單vue檔案會有一些不同:

import { Component, Vue } from "vue-property-decorator";
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src

@Component({
  components: {
    HelloWorld
  }
})
export default class Home extends Vue {}
複製程式碼
  • vue-property-decorator

    從示例中看出Component, Vue這些是從vue-property-decorator這個庫引入的,vue-property-decorator是個什麼呢?這是它的GitHub地址vue-property-decorator

    從它的介紹來看,它說這個庫是完全依賴另一個庫vue-class-component推薦先去閱讀這個庫的README,好吧,那隻能先去看看vue-class-component這個庫是什麼了。

    vue的官網中有提到:

    vue + typescript 踩坑筆記(一)

    我看了一些其他人寫的文章,簡單的說就是用typescript寫vue每次都需要寫一些額外形式的程式碼,vue-class-component通過裝飾器來減少這些重複的程式碼,vue-property-decorator則是在vue-class-component的基礎上增加了一些裝飾器。

    • 裝飾器

      在寫JavaScript的時候,基本是沒有接觸過裝飾器,還好之前學習Python的時候,接觸到了這方面的知識,簡單介紹下:

      #!/usr/bin/env python3
      # -*- coding: utf-8 -*-
      
      '''
      需求:想要給函式add和函式square增加執行時間列印功能
      '''
      
      def add(a, b):
          return a + b
      
      def square(a):
          return a ** 2
      複製程式碼

      方法一:直接在add和square執行前和執行後把時間列印出來即可:

      import time
      
      t1 = time.time()
      a = add(10, 20)
      print('add執行時間:%f' % (time.time() - t1))
      
      t2 = time.time()
      b = square(10)
      print('square執行時間:%f' % (time.time() - t2))
      複製程式碼

      方法二:將重複的程式碼封裝起來

      def print_execute_time(func):
      def wrap(*args, **kwargs):
          t1 = time.time()
          result = func(*args, **kwargs)
          print('%s執行時間:%f' % (func.__name__, time.time() - t1))
          return result
      return wrap
      
      print_execute_time(add)(10, 20)
      print_execute_time(square)(10)
      複製程式碼

      就是把需要執行的函式當做引數,給需要執行的函式包一層。

      方法三:使用裝飾者模式,在Python中是@裝飾函式名語法:

      #!/usr/bin/env python3
      # -*- coding: utf-8 -*-
      
      import time 
      
      def print_execute_time(func):
          def wrap(*args, **kwargs):
              t1 = time.time()
              result = func(*args, **kwargs)
              print('%s執行時間:%f' % (func.__name__, time.time() - t1))
              return result
          return wrap
      
      @print_execute_time  # 新增
          def add(a, b):
          return a + b
      
      @print_execute_time # 新增
      def square(a):
          return a ** 2
      
      
      add(10, 20)
      square(10)
      複製程式碼

      總結下就是,在不改寫函式體或者函式呼叫方式的情況下,給函式增加一些新功能。雖然這是Python的例子,但是概念還是差不多的,JavaScript中呢好像還處於提案階段,具體參考阮一峰大神的修飾器

    既然用了vue-property-decorator,那麼vue的寫法也就出現了一些不同,比如:

    import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src
    
    @Component({
        components: {
            HelloWorld
        }
    })
    export default class Home extends Vue {}
        // data
        msg = 'hello'
        name = 'home'
        
        // props
        @Prop({ default: "text" })
        type!: string;
        @Prop()
        placeholder!: string;
        
        // methods
        say_name(): void {
            console.log(this.name)
        }
    複製程式碼

    好在是vue-property-decorator這個庫給了不同裝飾器的用法示例,可以去GitHub上參考。

二. @Prop() private msg!: string;

在看vue-cli給出的示例中,HelloWorld這個元件中,prop的寫法是這樣,發現一個特殊的地方,就是msg後面加了一個!,在typescript中這種寫法的意思就是!前面的這個變數一定不是undefined或者null,!叫非空斷言操作符。文件

三. 當函式的引數是物件的時候

es6中加入瞭解構賦值這一新語法,所以我在寫函式的時候喜歡這樣寫:

    const obj = {
        name: 'allen',
        age: 18
    }
    
    function say_something({ name, age }) {
        console.log(name, age)
    }
複製程式碼

因為typescript中有靜態資料型別這個東西,就是在宣告變數的時候,就要定好該變數的型別,那麼在函式中引數也是需要給它定好一個型別的:

    // 一開始我以為只要寫Object就好了, 但是這樣會報錯
    
    const obj: Object = {
        name: 'allen',
        age: 18
    }

    function say_something({ name, age }: Object):void {
        console.log(name, age)
    }
    
    // 後來網上查了一下,需要寫成這樣:
    
    interface obj {
        name: string;
        age: number;
    }
    function say_something({ name, age }: obj):void {
        console.log(name, age)
    }
    
    // 或是這樣:
    
    function say_something({ name, age }: any):void {
        console.log(name, age)
    }
複製程式碼

四. Element implicitly has an 'any' type because type 'Set' has no index signature

這是一個報錯提示,出現在了我這樣寫的時候:

    export default class Test extends Vue {
        set_something(name: string, value: any):void {
            this[name] = value
        }
    }
複製程式碼

要解決這個問題,需要這樣寫:

    export default class Test extends Vue {
        set_something(name: string, value: any):void {
            interface IParams {
                [key: string]: any
            }
            (<IParams>this)[name] = value
        }
    }
複製程式碼

這就是目前碰到的一些小坑吧,在寫專案的過程中參考了以下文章:

目前還未體會到typescript的強大之處,感覺就是寫的很繁瑣。/(ㄒoㄒ)/~~

相關文章