In September of last year, Evan You (creator of Vue.js) announced plans for the next major version of the library. Vue 3.0 will feature an improved experience for TypeScript users, including native support for class-based components, and better support for type inference when writing code.
The great news is, you don’t have to wait until version 3.0 is released (predicted for Q3 of 2019) to start writing your Vue apps in TypeScript. Vue’s command-line tool, Vue CLI, comes with options for starting projects with the TypeScript build tooling pre-configured and includes the officially supported vue-class-component module, allowing you to write your Vue components as TypeScript classes.
This article assumes some familiarity with both Vue and the basics of TypeScript. Let’s take a look and see how you can start taking advantage of static typing and class-based components in your code today.
Starting a Vue + TypeScript Project
One hurdle to getting started with TypeScript can be configuring the necessary build tooling. Thankfully, Vue has us covered there with the Vue CLI. We can use it to create a project for us with the TypeScript compiler set up and ready to go.
Let’s briefly walk through creating a new Vue project with TypeScript support.
From the terminal/command line (and assuming you have Node.js installed), run the following command to install Vue CLI globally:
npm install -g @vue/cli
Next, let’s create a new project, specifying the name of the project:
vue create vue-typescript-demo
This will also be the name of the sub-folder the project is installed to. Once you hit
Choose the manual option, and you’ll be presented with a further set of options. The essential option is, obviously, TypeScript, but you might also want to select Vuex as we’ll be checking out some Vuex-specific decorators later on.
Having selected your project options, the next screen will ask you if you want to use the class-style component syntax. Say yes to this. You’ll then be asked if you want to ‘Use Babel alongside TypeScript for auto-detected polyfills’. This is a good idea for projects where you’ll be supporting older browsers. Answer the remaining questions as you see fit, and the installation process should start.
A Note on Editor/IDE Support
Many code editors and IDEs now have support for TypeScript. Among paid solutions, JetBrains software (e.g. WebStorm, PhpStorm) has excellent support for both Vue and TypeScript. If you’re looking for a free alternative, my recommendation is Microsoft’s Visual Studio Code: combined with the Vetur extension it provides great auto-completion and type checking.
Class-based Components
Let’s start by looking at how to write Vue components using classes. While this feature is not limited to TypeScript, using class-based components helps TS provide better type checking and, in my opinion, makes for cleaner, more maintainable components.
Let’s take a look at the syntax. If you followed along with the previous section and used Vue CLI to create a new project, go into the project directory, into the src sub-folder, and open App.vue. What we’re interested in here is the <script>
section, as it’s the only part that differs from a standard Vue single-file-component (SFC).
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from './components/HelloWorld.vue';
@Component({
components: {
HelloWorld,
},
})
export default class App extends Vue {}
</script>
Notice that the <script>
tag itself has a lang
attribute of ts set. This is important for the build tools and your editor to correctly interpret the code as TypeScript.
In order to declare a class-based component, you need to create a class that extends vue
(here it’s imported from the vue-property-decorator
package rather than the vue module directly).
The class declaration needs to be preceded by the @Component
decorator:
@Component
class MyComponent extends Vue {}
As you might have noticed in the code from the App.vue component, the decorator can also accept an object, which can be used to specify the components
, props
, and filters
options for the component:
@Component({
components: { MyChildComponent },
props: {
id: {
type: String,
required: true
}
},
filters: {
currencyFormatter
}
})
class MyComponent extends Vue {}
Data properties
When declaring object-based components, you’ll be familiar with having to declare your component’s data properties as a function that returns a data object:
{
data: () => ({
todos: [],
})
}
… whereas with class-based components, we can declare data properties as normal class properties:
@Component
class TodoList extends Vue {
todos: [];
}
Computed properties
Another advantage of using classes as components is the cleaner syntax for declaring computed properties, using getter methods:
@Component
class TodoList extends Vue {
// ...
get uncompletedTodos() {
return this.todos.filter(todo => todo.done === false);
}
}
Likewise, you can create writable computed properties by using a setter method:
set fullName(value: string) {
let names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[names.length - 1];
}
Methods
Component methods can be declared in a similarly clean way, as class methods:
@Component
class TodoList extends Vue {
// ...
addTodo(text) {
this.todos.push({ text, done: false });
}
}
In my opinion, the simple syntax for declaring methods, data properties, and computed properties makes writing and reading class-based components nicer than the original object-based ones.
Decorators
We can take things a step further, using the additional decorators provided by the vue-property-decorator package. It provides six additional decorators for authoring class-based components:
Let’s take a look at three of them that you’ll probably find the most useful.
@Prop
Rather than passing a props
configuration object to the @Component
decorator, you can use the @Props
decorator to declare your props as class properties.
@Component
class TodoItem extends Vue {
@Prop
todo;
}
As with other decorators, @Prop
can accept various arguments, including a type, an array of types, or an options object:
@Prop(String)
name;
@Prop([String, Null])
title;
@Prop({ default: true })
showDetails;
When using with TypeScript, you should suffix your prop names with the non-null operator (!) to tell the compiler that the prop will have a non-null value (as TS is not aware these values will be passed into the component when it’s initialized):
@Prop(String) name!: string;
Note that, as shown above, it’s perfectly OK to put the decorator and the property declaration on one line if you want.
@Emit
Another handy decorator is @Emit
, allowing you to emit an event from any class method. The event emitted will use the name of the method (with camelCase names being converted to kebab-case), unless an alternative event name is passed to the decorator.
If the method returns a value, this will be emitted as the event’s payload, along with any arguments passed to the method.
@Emit()
addTodo() {
return this.newTodo;
}
The above code will emit an ‘add-todo’ event with the value of this.newTodo
as the payload.
@Watch
Creating watchers is nice and simple with this decorator. It takes two arguments: the name of the property being observed, and an optional options object.
@Watch('myProp')
onMyPropChanged(val: string, oldVal: string) {
// ...
}
@Watch('myObject', { immediate: true, deep: true })
onMyObjectChanged(val: MyObject, oldVal: MyObject) { }
Summing Up
I hope this article has shown you that starting to write your Vue apps in TypeScript doesn’t have to be a headache. By using the CLI to start new projects, you can quickly set up the necessary build tooling. The included support for class-based components and the additional decorators will have you writing clean, idiomatic TypeScript in no time!
Want to learn Vue.js from the ground up? Get an entire collection of Vue books covering fundamentals, projects, tips and tools & more with SitePoint Premium. Join now for just $9/month or try our 7 day free trial.
Frequently Asked Questions (FAQs) about Class-Based Vue.js with TypeScript
What are the benefits of using TypeScript with Vue.js?
TypeScript offers static typing, which can be a significant advantage when developing large-scale applications. It helps catch errors early in the development process, making the code more robust and maintainable. TypeScript also provides better autocompletion, navigation, and refactoring services, making the development process more efficient. When used with Vue.js, TypeScript allows for a more structured and scalable codebase, making it easier to manage and develop complex applications.
How do I set up a Vue.js project with TypeScript?
Setting up a Vue.js project with TypeScript involves a few steps. First, you need to install Vue CLI, if you haven’t already. Then, create a new project using Vue CLI and select TypeScript as a feature during the creation process. Vue CLI will set up a TypeScript configuration for you. You can then start writing Vue components using TypeScript.
What is a class-based component in Vue.js?
A class-based component in Vue.js is a way of defining components using ES6 classes. This approach can make your components more readable and easier to understand, especially for developers coming from an object-oriented programming background. Class-based components also work well with TypeScript, allowing you to leverage TypeScript’s features like static typing and interfaces.
How do I define a class-based component in Vue.js with TypeScript?
To define a class-based component in Vue.js with TypeScript, you need to use the vue-class-component
decorator. This decorator allows you to write your component as an ES6 class. Inside the class, you can define your data, methods, and lifecycle hooks just like you would in a regular Vue component.
Can I use Vue.js directives in class-based components?
Yes, you can use Vue.js directives in class-based components. The syntax is the same as in regular Vue components. You can use directives like v-model
, v-if
, v-for
, etc., in your template.
How do I use props in class-based components?
In class-based components, you can define props using the @Prop
decorator. This decorator allows you to specify the type of the prop and whether it’s required or has a default value.
How do I use computed properties in class-based components?
In class-based components, you can define computed properties as getter methods in your class. The result of the getter method will be cached and only re-evaluated when its dependencies change.
How do I use watchers in class-based components?
In class-based components, you can define watchers using the @Watch
decorator. This decorator allows you to specify the property to watch and the method to call when the property changes.
Can I use mixins in class-based components?
Yes, you can use mixins in class-based components. You can define a mixin as a class and then use the @Mixins
decorator to include it in your component.
How do I use the Vue.js Composition API with TypeScript?
The Vue.js Composition API works well with TypeScript. You can define your reactive data and functions inside the setup
method and use TypeScript to type them. This allows you to leverage TypeScript’s static typing and autocompletion features, making your code more robust and easier to develop.
Nilson is a full-stack web developer who has been working with computers and the web for over a decade. A former hardware technician, and network administrator. Nilson is now currently co-founder and developer of a company developing web applications for the construction industry. You can also find Nilson on the SitePoint Forums as a mentor.