最近在用 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的官网中有提到:

    我看了一些其他人写的文章,简单的说就是用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ㄒ)/~~

转载于:https://juejin.im/post/5c6fc8e0e51d4574704086c7

Logo

前往低代码交流专区

更多推荐