|
| 1 | +--- |
| 2 | +title: TypeScript Support |
| 3 | +type: guide |
| 4 | +order: 25 |
| 5 | +--- |
| 6 | + |
| 7 | +## Official Declaration Files |
| 8 | + |
| 9 | +A static type system can help prevent many potential runtime errors, especially as applications grow. That's why Vue ships with [official type declarations](https://github.com/vuejs/vue/tree/dev/types) for [TypeScript](https://www.typescriptlang.org/) - not only in Vue core, but also [for Vue Router](https://github.com/vuejs/vue-router/tree/dev/types) and [for Vuex](https://github.com/vuejs/vuex/tree/dev/types) as well. |
| 10 | + |
| 11 | +Since these are [published on NPM](https://unpkg.com/vue/types/), you don't even need external tools like `Typings`, as declarations are automatically imported with Vue. That means all you need is a simple: |
| 12 | + |
| 13 | +``` ts |
| 14 | +import Vue = require('vue') |
| 15 | +``` |
| 16 | + |
| 17 | +Then all methods, properties, and parameters will be type checked. For example, if you misspell the `template` component option as `tempate` (missing the `l`), the TypeScript compiler will print an error message at compile time. If you're using an editor that can lint TypeScript, such as [Visual Studio Code](https://code.visualstudio.com/), you'll even be able to catch these errors before compilation: |
| 18 | + |
| 19 | + |
| 20 | + |
| 21 | +### Compilation Options |
| 22 | + |
| 23 | +Vue's declaration files require the `--lib DOM,ES2015.Promise` [compiler option](https://www.typescriptlang.org/docs/handbook/compiler-options.html). You can pass this option to the `tsc` command or add the equivalent to a `tsconfig.json` file. |
| 24 | + |
| 25 | +### Accessing Vue's Type Declarations |
| 26 | + |
| 27 | +If you want to annotate your own code with Vue's types, you can access them on Vue's exported object. For example, to annotate an exported component options object (e.g. in a `.vue` file): |
| 28 | + |
| 29 | +``` ts |
| 30 | +import Vue = require('vue') |
| 31 | + |
| 32 | +export default { |
| 33 | + props: ['message'], |
| 34 | + template: '<span>{{ message }}</span>' |
| 35 | +} as Vue.ComponentOptions<Vue> |
| 36 | +``` |
| 37 | + |
| 38 | +## Class-Style Vue Components |
| 39 | + |
| 40 | +Vue component options can easily be annotated with types: |
| 41 | + |
| 42 | +``` ts |
| 43 | +import Vue = require('vue') |
| 44 | + |
| 45 | +// Declare the component's type |
| 46 | +interface MyComponent extends Vue { |
| 47 | + message: string |
| 48 | + onClick (): void |
| 49 | +} |
| 50 | + |
| 51 | +export default { |
| 52 | + template: '<button @click="onClick">Click!</button>', |
| 53 | + data: function () { |
| 54 | + return { |
| 55 | + message: 'Hello!' |
| 56 | + } |
| 57 | + }, |
| 58 | + methods: { |
| 59 | + onClick: function () { |
| 60 | + // TypeScript knows that `this` is of type MyComponent |
| 61 | + // and that `this.message` will be a string |
| 62 | + window.alert(this.message) |
| 63 | + } |
| 64 | + } |
| 65 | +// We need to explicitly annotate the exported options object |
| 66 | +// with the MyComponent type |
| 67 | +} as Vue.ComponentOptions<MyComponent> |
| 68 | +``` |
| 69 | + |
| 70 | +Unfortunately, there are a few limitations here: |
| 71 | + |
| 72 | +- __TypeScript can't infer all types from Vue's API.__ For example, it doesn't know that the `message` property returned in our `data` function will be added to the `MyComponent` instance. That means if we assigned a number or boolean value to `message`, linters and compilers wouldn't be able to raise an error, complaining that it should be a string. |
| 73 | + |
| 74 | +- Because of the previous limitation, __annotating types like this can be verbose__. The only reason we have to manually declare `message` as a string is because TypeScript can't infer the type in this case. |
| 75 | + |
| 76 | +Fortunately, [vue-class-component](https://github.com/vuejs/vue-class-component) can solve both of these problems. It's an official companion library that allows you to declare components as native JavaScript classes, with a `@Component` decorator. As an example, let's rewrite the above component: |
| 77 | + |
| 78 | +``` ts |
| 79 | +import Vue = require('vue') |
| 80 | +import Component from 'vue-class-component' |
| 81 | + |
| 82 | +// The @Component decorator indicates the class is a Vue component |
| 83 | +@Component({ |
| 84 | + // All component options are allowed in here |
| 85 | + template: '<button @click="onClick">Click!</button>' |
| 86 | +}) |
| 87 | +export default class MyComponent extends Vue { |
| 88 | + // Initial data can be declared as instance properties |
| 89 | + message: string = 'Hello!' |
| 90 | + |
| 91 | + // Component methods can be declared as instance methods |
| 92 | + onClick (): void { |
| 93 | + window.alert(this.message) |
| 94 | + } |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +With this syntax alternative, our component definition is not only shorter, but TypeScript can also infer the types of `message` and `onClick` without explicit interface declarations. This strategy even allows you to handle types for computed properties, lifecycle hooks, and render functions. For full usage details, see [the vue-class-component docs](https://github.com/vuejs/vue-class-component#vue-class-component). |
0 commit comments