How to use computed props in Vue.js with TypeScript?

You can use property accessors to declare computed properties. See Vue Class Component. The getter will be triggered as soon as you type in the input.

For example:

<template>
    <div>
        <input type="text" name="Test Value" id="" v-model="text">

        <label>{{label}}</label>
    </div>

</template>

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

@Component({})
export default class About extends Vue {
    private text = "test";

    get label() {
        return this.text;
    }
}
</script>

Update for Vue Composition Api

<template>
  <div>
    <input type="text" name="Test Value" id v-model="text" />

    <label>{{label}}</label>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, computed } from "@vue/composition-api";

export default defineComponent({
  setup() {
    const text = ref("test");

    const label = computed(() => {
      return text.value;
    });

    return {
      text,
      label
    };
  }
});
</script>

Because of the circular nature of Vue’s declaration files, TypeScript may have difficulties inferring the types of certain methods. For this reason, you may need to annotate the return type on methods like render and those in computed.

import Vue, { VNode } from 'vue'

const Component = Vue.extend({
  data () {
    return {
      msg: 'Hello'
    }
  },
  methods: {
    // need annotation due to `this` in return type
    greet (): string {
      return this.msg + ' world'
    }
  },
  computed: {
    // need annotation
    greeting(): string {
      return this.greet() + '!'
    }
  },
  // `createElement` is inferred, but `render` needs return type
  render (createElement): VNode {
    return createElement('div', this.greeting)
  }
})

If you find type inference or member completion isn’t working, annotating certain methods may help address these problems. Using the --noImplicitAny option will help find many of these unannotated methods.

More Info


Vite Vue 3.2+ TypeScript

<template>
    <input type="text" v-model="title" />
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { useStore } from 'vuex';

const store = useStore()

const title = computed({
    get: () => store.state.page.about.title,
    set: value => store.commit('setData', { about: { title: value }})
})
</script>

Mutation setData in store

setData(state: { about: any, blog: any, contact: any, home: any }, data: any) {
     if (data['about']) state.about = { ...state.about, ...data.about }
     if (data['blog']) state.blog = { ...state.blog, ...data.blog }
     if (data['contact']) state.contact = { ...state.contact, ...data.contact }
     if (data['home']) state.home = { ...state.home, ...data.home }
}

Function above by using spread operator ... will overwrite object field you send to them.