Oyetoke Tobi Software engineer passionate about building developers tools and open source contributions.

Define properties with Vue Property Decorator and TypeScript

4 min read 1274

Vue Property Decorator

Vue 3 introduced a new, better way to create components, the Composition API. The Composition API’s features make it possible to better maintain code as components grow, reuse code easily, and write reliable code, all while providing TypeScript support.

However, Vue components rely heavily on the JavaScript object’s this keyword, making it confusing to create a TypeScript object. To solve this issue, the Vue Class Component plugin uses ECMAScript decorators to pass statically typed values directly to components in Vue, making the compiler understand what is happening.

In this article, you’ll learn how to define properties like data, methods, computed properties, props, and watchers directly on the class in Vue components by supporting TypeScript in Vue class-based components. We’ll use Vue Class Component and Vue Property Decorator, and we’ll also cover the various JavaScript equivalents.

Prerequisites

To follow along with this tutorial, you’ll need knowledge of TypeScript. You’ll also need npm and Node.js v12.22.0 installed on your local machine. To confirm that Node.js is installed, run the following command in your terminal:

node -v

If you don’t have Node.js installed, you can follow the instructions on the official Node.js website. Lastly, you’ll need familiarity with setting up a Vue project. Let’s get started!

Table of contents

Project setup

Open your terminal and cd into the directory where you want to save the project. Run the following command. Note that you can name your project whatever you like:

vue create vue-props-example

While setting up your Vue project, you’ll be asked a series of questions. For the purpose of this tutorial, you should choose the following configurations:

Prompt Option
Please pick a preset Manually select features
Check the features needed for your project TypeScript
Choose a version of Vue that you want to start the project with 3.x
Use class-style component syntax? Y
Use Babel alongside TypeScript? Y

 

Vue Configurations Display

If you look at the package.json file, you’ll see that by installing our project with TypeScript, we also install the vue-class-component plugin, which is used to define class-style components and is installed by default when a TypeScript and Vue 3 project is created.

The App.vue file uses Vue Class Component, which uses the Options decorator to define a Vue component. At this point, you have a Vue 3 project that includes the power of TypeScript.

Installing Vue Property Decorator

Some of the most important parts of Vue are missing in Vue Class Component, for example, ECMAScript decorators like props, inject, model, ref, emit, and provide. As a result, the Vue community introduced a library called Vue Property Decorator, which fully depends on the Vue Class Component and is now fully endorsed by the Vue core team.

We’ll install Vue Property Decorator in our project by running the following command in the project directory:

npm i vue-property-decorator

Now, we can fully use class-based components in TypeScript.

Creating a TypeScript Vue component

With the class-style component syntax, we’ll build components by extending the Vue object. In App.vue, copy and paste the following code to create a simple single-file component with TypeScript:

<template>
  <div>
    <label>Update inputData
      <input :value="inputData" @input="updateInputData($event)"/>
    </label>
    <div>{{ inputData }}</div>
  </div>
</template>

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

@Component
export default class App extends Vue {
  // Data property
  inputData: string = 'My Input Data'

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

The code above defines properties directly on the class and methods, which is possible with the help of the @Component(componentConfig) decorator. During the compilation, the @Component(componentConfig) decorator transforms the class into a format Vue can understand.

Now, when the app is compiled, if you look at your browser at http://localhost:8080/, you’ll see an input field and some text reading myInputData. myInputData will interact with the input field, updating accordingly to reflect the changes made to the user’s input texts on the browser.

Defining props

With the @Prop decorator from the Vue Property Decorator library, we can define props on the class. We can also provide additional details for props, like required, type, and default to allow reusability of data objects.

We first import the Prop decorator from the Vue Property Decorator library and write the following code:

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

@Component
export default class App extends Vue {
  @Prop() readonly text!: string
  @Prop({default: 'John doe'}) readonly name: string
  @Prop({required: true}) readonly age: number
  @Prop(String) readonly phone: string
  @Prop({required: true, type: String, default: 'Student'}) readonly job: string
}
</script>

The code above, written in TypeScript, defines various props called text, name, age, phone, and job. To avoid modifying the prop, the readonly attribute is assigned.

In JavaScript, the code above is equivalent to the following:

&lt;script>
export default {
  props: {
    text,
    name: {
      default: 'John doe'
    },
    age: {
      required: true,
    },
    phone: {
      type: String
    },
    job: {
      required: true,
      type: String,
      default: 'Student'
    }
  }
}
</script>

Defining computed properties

Computed properties are written as getters and setters and defined on the class. To demonstrate, the example below contains computed properties in TypeScript that get a computed property called computedProp and return a random number, displaying it on the browser:

<template>
  <div>{{ computedProp }}</div>
</template>

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

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

The JavaScript equivalent to the code above is:

<style>
export default {
  computed: {
    computedProp() {
      return Math.random()
    }
  }
}
</style>

Defining watchers

We can define watchers on the class by importing the @Watch(propertyString, config) decorator from the Vue Property Decorator library. You’ll notice this is quite different from how it’s normally written in JavaScript.

Below is an example in TypeScript that watches for when myWatchedData triggers onDataChanged:

<template>
  <div>
    <label>Update myWatchedData
      <input :value="myWatchedData" @input="updateMyData($event)"/>
    </label>
    <div>{{ myWatchedDataStatus }}</div>
  </div>
</template>

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

@Component
export default class App extends Vue {
  myWatchedData: string = 'Watched Data'
  myWatchedDataStatus: string = ''

  @Watch('myWatchedData')
  onDataChanged(value: string, oldValue: string) {
    this.myWatchedDataStatus = 'Watched Data Changed'
  }

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

The JavaScript equivalent to the code above is:

&lt;script>
export default {
  data() {
    return {
      myWatchedProperty: null
    }
  }

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

  watch: {
    myWatchedProperty: {
      handler: 'onPropertyChanged',
      immediate: false,
      deep: true
    }
  }
}
</script>

With the code above, when you visit the browser at http://localhost:8080/, you’ll see an input field. Now, changing the input value will display the message Watched Data Changed.

Conclusion

In this article, we used Vue Class Component and Vue Property Decorator to define properties directly on the class in Vue components, allowing us to support TypeScript in Vue class-based components.



This article introduced various decorators likecomponent, prop, watch, get. You can learn more about decorators and class-based declarations in the documentation for Vue Class Component and Vue Property Decorator linked above.

Creating Vue components with TypeScript may be a bit confusing, for starters, but when you get used to it, you get to enjoy all the benefits that it brings, making your application more reliable. I hope you enjoyed this article, happy coding!

Experience your Vue apps exactly how a user does

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - .

Oyetoke Tobi Software engineer passionate about building developers tools and open source contributions.

3 Replies to “Define properties with Vue Property Decorator and TypeScript”

  1. I only got as far as “Creating a TypeScript Vue component” before it all blew up!

    ERROR in src/App.vue:14:2

    TS1238: Unable to resolve signature of class decorator when called as an expression.
    This expression is not callable.
    Type ‘typeof import(“/home/mark/repos/vue-props-example/node_modules/vue-class-component/dist/vue-class-component”)’ has no call signatures.
    12 | import { Component, Vue } from “vue-property-decorator”;
    13 |
    > 14 | @Component

  2. is there a solution to this not working? I just can’t get vue-property decorator to work at all

Leave a Reply