Writing Class-Based Components with Vue.js and TypeScript

Joshua Bemenderfer

Those from an Angular (2+) background are probably familiar with the pattern of writing components as classes using properties and decorators to describe more complex parts of your component. Well, with a little configuration work, you can do the same thing with Vue! The biggest advantage class-based components have over standard Vue components is that they make it clearer where this actually points to in the compiled component, and allow for more concise code.

Installation

You will need vue-class-component and vue-property-decorator installed, along with the usual webpack, typescript, and ts-loader dependencies. (If you need help with the latter set, see the configuration used in the vue-class-component examples).

# Install using Yarn
$ yarn add vue-class-component vue-property-decorator -D

# Or install using NPM
$ npm install vue-class-component vue-property-decorator --save-dev

Your First Class Component

A class component is simply a TypeScript class that extends the Vue object. In single-file components, as shown below, make sure you set the <script> language to ts and export the class as default.

<template>
  <div>
    <p>Long-form v-model example</p>
    <input :value="myDataProperty" @input="updateMyProperty($event)"/>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import { Component } from 'vue-property-decorator'

@Component
export default class App extends Vue {
  // Data property
  myDataProperty: string;

  // Lifecycle hook
  mounted () {
    this.myDataProperty = 'Boop'
  }

  // Component method
  updateMyProperty ($event) {
    this.myDataProperty = $event.target.value
  }
}
</script>

The first thing you’ll probably notice is that data properties are defined directly on the class. Methods are as well. The @Component(componentConfig) decorator is what makes this possible. It transforms the class into a format that Vue can understand during the compilation process.

Component Props

Through the use of the @Prop(config) decorator from vue-property-decorator, we can declare input properties in much the same way as data properties.

import { Component, Prop } from 'vue-property-decorator'

@Component
export default class App extends Vue {
  // Makes a "exampleProperty" a component prop with the default value of 'Example'
  @Prop({default: 'Example'})
  exampleProperty: string
}

Which is the same as:

export default {
  props: {
    exampleProperty: {
      type: String,
      default: 'Example'
    }
  }
}

Computed Properties

Computed properties are written as getters and setters on the class.

import { Component } from 'vue-property-decorator'

@Component
export default class App extends Vue {
  get myComputedProp() {
    return Math.random()
  }
}

Which is equivalent to:

export default {
  computed: {
    myComputedProp() {
      return Math.random()
    }
  }
}

Watchers

Watchers can be created with the @Watch(propertyString, config) decorator.

import { Component } from 'vue-property-decorator'

@Component
export default class App extends Vue {
  myProperty: string

  @Watch('myProperty')
  onPropertyChanged(value: string, oldValue: string) {
    // Do stuff with the watcher here.
  }
}

Which is considerably more succinct than the verbose vanilla Vue version: (Points for alliteration!)

export default {
  data: () => ({
    myProperty: null
  })

  methods: {
    onPropertyChanged(value, oldValue) {

    }
  }

  watch: {
    'myProperty': {
      handler: 'onPropertyChanged',
      // These can be configured in an object as the second argument to @Watch()
      immediate: false,
      deep: true
    }
  }
}

Class-based components aren’t for everyone, but if you understand them and enjoy working with TypeScript, you’ll probably find them to be great way to write Vue components even more succinctly and clearly than you normally would.

✖ Clear

🕵 Search Results

🔎 Searching...