w3resource
Vue Tutorial

TypeScript Support

The Vue CLI provides built-in TypeScript tooling support.

Official Declaration in NPM Packages

A static type system can help prevent many potential runtime errors when building applications, especially as applications grow. This is why Vue ships with official type declarations for TypeScript- not just in Vue core alone, but also for vuex and vue-router as well.

Since these packages are published on NPM, and the lates TypeScript knows how to resolve type in an NPM package, this means that when a package is installed via NPM, we don't need any additional tooling to use TypeScript with Vue.

Recommended Configuration

// tsconfig.json
{
  "compilerOptions": {
    // this will align with Vue's browser support
    "target": "es5",
    // this will enable stricter inference for data properties on `this`
    "strict": true,
    // if using rollup or webpack 2+, in leveraging tree shaking:
    "module": "es2015",
    "moduleResolution": "node"
  }
}

Note that we have to include strict:true (or at least noImplicitThis:true which is a part of the strict flag) to leverage type checking of this in component methods otherwise it will always be treated as any type.

Development Tooling

Project Creation

The Vue CLI 3 can generate new projects that use TypeScript. To start off:

  1. Install the Vue CLI, if it's not already installed in your PC
  2. npm install --global @vue/cli
  3. This will create a new project, and then choose the "Manually select features" option
  4. vue create my-project-name

Editor Support

Visual Studio Code is strongly recommended for developing Vue applications with TypeScript. This is because it provides great out-of-the-box support for TypeScript. If you will be using single-file-components, I recommended that you get the awesome Vetur extension, this will provide TypeScript inference inside SFCs and many other great features.

WebStorm is an alternative as it provides out-of-the-box support for both TypeScript and Vue.

Basic Usage

If we want to let TypeScript properly infer types inside Vue component options, we need to define components with Vue.component or Vue.extend:

import Vue from 'vue'
const Component = Vue.extend({
  // type inference is enabled
})
const Component = {
  // have type inference will not be enabled here,
  // because TypeScript can't tell that this is options for a Vue component.
}

Class-Style Vue Components

In case you prefer a class-based API when declaring components, you could use the officially maintained vue-class-component decorator:

import Vue from 'vue'
import Component from 'vue-class-component'

// The @Component decorator indicates that the class is a Vue component
@Component({
  // All component options will be allowed in here
  template: '<button @click="onClick">Click!</button>'
})
export default class MyComponent extends Vue {
  // the initial data can be declared as instance properties
  message: string = 'Hello!'

  //The Component methods can be declared as instance methods
  onClick (): void {
    window.alert(this.message)
  }
}

Augmenting Types for Use with Plugins

We can add plugins to Vue's global/instance properties and component options. In cases as these, type declarations are needed to make plugins to compile in TypeScript. There is a TypeScript feature that augments existing types called module augmentation.

Take for instance, if we want to declare an instance property $myProperty with type string:

// 1. Make sure to import 'vue' before declaring augmented types
import Vue from 'vue'
// 2. Specify a file with the types you want to augment
//    Vue.JS has the constructor type in types/vue.d.ts
declare module 'vue/types/vue' {
  // 3. Declare the augmentation for Vue
  interface Vue {
    $myProperty: string
  }
}

After including the above code as a declaration file (like my-property.d.ts) in our project, we can use $myProperty on a Vue instance.

var vm = new Vue()
console.log(vm.$myProperty) // This should hopefully compile successfully

We can also declare additional global properties and component options:

import Vue from 'vue'
declare module 'vue/types/vue' {
  // the global properties can be declared on
  // the `VueConstructor` interface
  interface VueConstructor {
    $myGlobal: string
  }
}

//  the ComponentOptions is declared in types/options.d.ts
declare module 'vue/types/options' {
  interface ComponentOptions<V extends Vue> {
    myOption?: string
  }
}

The above declarations will allow the following code to be compiled:

// Global property
console.log(Vue.$myGlobal)

// Additional component option
var vm = new Vue({
  myOption: 'Hello'
})

Annotating Return Types

Due to the circular nature of Vue's declaration files, TypeScript may have some difficulties inferring the types of certain methods. Hence, we may need to annotate the return type on methods like render and those in computing.

import Vue, { VNode } from 'vue'
const Component = Vue.extend({
  data () {
    return {
      msg: 'Hello'
    }
  },
  methods: {
    // we need annotation due to `this` in return type
    greet (): string {
      return this.msg + ' world'
    }
  },
  computed: {
    // need annotation
    greeting(): string {
      return this.greet() + '!'
    }
  },
  //the `createElement` is inferred, but `render` will need return type
  render (createElement): VNode {
    return createElement('div', this.greeting)
  }
})

If we find type inference or that member completion isn't working, then annotating certain methods may help address these problems. Use of the --noImplicitAny option will help find many of these unannotated methods.