Tutorial

How To Write Class-Based Components with Vue.js and TypeScript

Updated on March 16, 2021
Default avatar

By Joshua Bemenderfer

How To Write Class-Based Components with Vue.js and TypeScript

Introduction

Vue.js 2 supports class-style components. If you are coming from an Angular (2+) background, you are probably familiar with the pattern of writing components as classes using properties and decorators to describe more complex parts of your component.

The biggest advantage class-style components have over standard Vue.js components is that they make it clearer where this actually points to in the compiled component, and allow for more concise code.

In this article, you will be introduced to using vue-class-component and vue-property-decorator to support TypeScript in Vue.js class-based components.

Prerequisites

To follow along with this article, you will need:

This tutorial was verified with Node v15.1.0, npm v6.14.8, Vue.js v2.6.11, TypeScript v3.9.3, @vue/cli v4.5.0, vue-class-component v7.2.3, and vue-property-decorator v8.4.2.

Step 1 — Setting Up the Project

You will need vue-class-component and vue-property-decorator installed.

You can use @vue/cli to create a new Vue.js project:

  1. npx @vue/cli create vue-typescript-example

For the purposes of this tutorial, the configuration will require:

Prompt Option
Please pick a preset Manually select features
Check the features needed for your project TypeScript
Use class-style component syntax? Yes

@vue/-plugin-typescript will install typescript, vue-class-component, and vue-property-decorator.

Then, navigate to the project directory:

  1. cd vue-typescript-example

At this point, you have a Vue.js project set up for TypeScript and class-style components.

Step 2 — Writing a Single-File Component with TypeScript

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

Open App.vue in your code editor and create this example single-file component with TypeScript:

src/App.vue
<template>
  <div>
    <label>Update myDataProperty
      <input :value="myDataProperty" @input="updateMyProperty($event)"/>
    </label>
    <div>{{ myDataProperty }}</div>
  </div>
</template>

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

@Component
export default class App extends Vue {
  // Data property
  myDataProperty: string = 'Data Property'

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

Notice that the data properties are defined directly on the class and methods.

The @Component(componentConfig) decorator is what makes this possible. It transforms the class into a format that Vue.js can understand during the compilation process.

At this point, if you were to compile and observe your application in a browser, you would be presented with an input field and the word Data Property. By interacting with the input field, myDataProperty will be updated and reflect the changes that are made.

Step 3 — Using Component Props

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

Here is an example in TypeScript that takes a exampleProperty a component prop with the default value of 'Input Property':

src/App.vue
<template>
  <div>{{ exampleProperty }}</div>
</template>

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

@Component
export default class App extends Vue {
  @Prop({ default: 'Input Property' })
  exampleProperty!: string
}
</script>

In JavaScript, this is equivalent to:

export default {
  props: {
    exampleProperty: {
      type: String,
      default: 'Input Property'
    }
  }
}

At this point, if you were to compile and observe your application in a browser, you would be presented with the message: Input Property.

Step 4 — Using Computed Properties

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

Here is an example in TypeScript that gets a myComputedProp and returns a random number:

src/App.vue
<template>
  <div>{{ myComputedProp }}</div>
</template>

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

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

In JavaScript, this is equivalent to:

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

At this point, if you were to compile and observe your application in a browser, you would be presented with a random number.

Step 5 — Using Watchers

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

Here is an example in TypeScript that watches for when myWatchedProperty triggers onPropertyChanged:

src/App.vue
<template>
  <div>
    <label>Update myWatchedProperty
      <input :value="myWatchedProperty" @input="updateMyProperty($event)"/>
    </label>
    <div>{{ myWatchedPropertyStatus }}</div>
  </div>
</template>

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

@Component
export default class App extends Vue {
  myWatchedProperty: string = 'Watched Property'
  myWatchedPropertyStatus: string = ''

  @Watch('myWatchedProperty')
  onPropertyChanged(value: string, oldValue: string) {
    this.myWatchedPropertyStatus = 'Watched Property Changed'
  }

  updateMyProperty ($event: { target: { value: string } }) {
    this.myWatchedProperty = $event.target.value
  }
}
</script>

In JavaScript, this is equivalent to:

export default {
  data() {
    return {
      myWatchedProperty: null
    }
  }

  methods: {
    onPropertyChanged(value, oldValue) {
      // ...
    }
  }

  watch: {
    myWatchedProperty: {
      handler: 'onPropertyChanged',
      immediate: false,
      deep: true
    }
  }
}

At this point, if you were to compile and observe your application in a browser, you would be presented with an input field. Changing the input value will display the message Watched Property Changed.

Conclusion

In this article, you learned how to use vue-class-component and vue-property-decorator to support TypeScript in Vue.js class-based components.

This article introduced @Component, get, and set. For a full list of declarations available from vue-class-component, consult the official documentation.

This article also introduced @Prop, and @Watch. For a full list of decorators available from vue-property-decorator, consult the official documentation.

If you’d like to learn more about TypeScript, check out our TypeScript topic page for exercises and programming projects.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Joshua Bemenderfer

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
2 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Hi! What’s the right way to register local components with vue-property-decorator? I tried smth like this, but still get errors

import { Component, Prop, Vue } from 'vue-property-decorator';
import { Cell, Loading, ErrorState } from './results';

@Component
export default class ResultsCard extends Vue {
  components = {
    Cell,
    Loading,
    ErrorState,
  }
}

Registering in objects also not working

@Component
export default class ResultsCard extends Vue {
  components: {
    Cell,
    Loading,
    ErrorState,
  }
}
import { Component, Watch } 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.
  }
}
code

Watch needs to be imported as well I think

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel