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.

Recommended: Vue School's Vue Master class course

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() {
    return {
      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.

  Tweet It

๐Ÿ•ต Search Results

๐Ÿ”Ž Searching...

Sponsored by #native_company# โ€” Learn More
#native_title# #native_desc#
#native_cta#