TypeScript support for Vue.js - 1.3

Supported versions

Component Version Support
Vuejs v2.x, v3.x
Vuex v2.x, v3.x, v4.x
Pinia v1.x, v2.x

What results can you expect?

In Vue3, components can be authored in two different API styles: Options API and Composition API. Both approaches are supported. This extension creates links to TypeScript Methods or Functions that are used as:

  • Vuejs methods
  • Vuejs computed that are used to calculate computed properties
  • Vuejs watchers that are executed anytime a reactive variable changes
  • Vuex actions
  • Vuex mutations
  • Vuex getters
  • Pinia actions
  • Pinia getters

This extension will create a callLink to vue.js methods called from:

  • another vue.js method, computed or watcher (in the following example the increment_twice method calls the increment method)
  • an html5 fragment or source code containing a tag having an attribute starting with “@” and whose value corresponds to the name of a method (see link to the increment method from the App.vue)
  • an html5 fragment or source code containing a function call within an interpolation:
    • in a text interpolation also known as mustache syntax (see call to the square method in the following example)
    • in the argument of a directive attribute (see calls to the increment method or greater_than1 method in the following example)

Thus when analyzing the following source code:

<script lang="ts">
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    },
    increment_twice(){
      this.increment()
      this.increment()
    },
    square(){
      return this.count * this.count
    },
    greater_than1(){
      return this.count > 1 ? true : false
    }
  },
}
</script>
        
<template>
  <h1>The count is {{ count }}</h1>
  <button @click="increment">
    increment
  </button>
  <button @click="increment_twice">
    increment twice
  </button>
  <h2>The square of the count is {{ square() }}</h2>
  <h2 v-if="greater_than1()"> Count is larger than 1 </h2>
</template>

you will get the following result:

This extension will create a callLink to vue.js computed from:

  • another vue.js method, computed or watcher (in the following example the decrement method calls the greater_than0 computed)
  • an html5 fragment or source code containing a reference to a computed within an interpolation in the argument of a directive attribute (see calls to the greater_than0 computed in the following example)

Thus when analyzing the following source code:

<script lang="ts">
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    decrement(){
      if (this.greater_than0) {
        this.count--
      }
    }, 
  },
  computed:{
    square(){
      return this.count * this.count
    },
    greater_than0(){
      return this.count > 0 ? true : false
    }
  }
}
</script>
        
<template>
  <h1>The count is {{ count }}</h1>
  <button @click="decrement">
    decrement
  </button>
  <h2>The square of the count is {{ square }}</h2>
  <h2 v-if="greater_than0"> Count is larger than 0 </h2>
</template>

you will get the following result:

In Vue.js, a watcher function is called whenever its associated variable is modified.
The com.castsoftware.vuejs extension creates a callLink to a vue.js watcher whenever a modification of variables made with a simple assignment or using the increment (++) or decrement (–) operator. These modifications are checked within:

  • another vue.js method, computed or watcher (see call from the stockPlus2 function)
  • the argument of a directive attribute in an html5 fragment (see call from the html5 fragment to the Anonymous1 function that corresponds to the arrow function passed as second argument to the watch call)

Thus when analyzing the following source code:

<script setup lang="ts">
import { ref, watch } from 'vue'

const stock = ref(4)

const warning = ref('')

function stockPlus2() {
  stock.value = stock.value + 2
}

watch(stock, async ()=>{
  if (stock.value < 3) {
    warning.value = 'The stock is too low. Ordering...'
  }
  else {
    warning.value = ''
  }
})
</script>
        
<template>
  <p>The stock is: {{ stock }}</p>
  <button @click="stock = stock + 1" >Add one</button>
  <h3>{{ warning }}</h3>

</template>

you will get the following results:

A Vuex action can be called from:

  • a Vue component using this.$store.dispatch() (see call from the created method to the increment action in the following example)
  • a Vuex action or mutation using the context that the handler gets from its parameter (see call from incrementtwice to increment in the following example)

Also an action can be mapped with a method using the MapAction api. A callLink is created to the mapped action whenever its corresponding method is called. In the following example a callLink is created from the Counter.vue Source Code to the incrementtwice action due to the @click=“incrementtwice” in the vue.

Thus when analyzing the following source codes:

// index.ts

import { createApp } from 'vue'
import Counter from './Counter.vue'
import store from './store'

const app = createApp(Counter)
app.use(store)
app.mount('#app')
// Counter.vue

<template>
  <div id="app">
    Clicked: {{ $store.state.count }} times, count is {{ evenOrOdd }}.
    <button @click="incrementtwice">+</button>
    <button @click="increment">-</button>
  </div>
</template>

<script lang="ts">
import { mapGetters, mapActions } from 'vuex'

export default {
  computed: mapGetters([
    'evenOrOdd'
  ]),
  methods: mapActions([
    'incrementtwice',
    'increment'
  ]),
  
  created(){
     this.$store.dispatch('increment')
  }
}
</script>
//store.ts

import { createStore } from 'vuex'

// root state object.
// each Vuex instance is just a single state tree.
const state = {
  count: 0
}

const actions = {
  incrementtwice(context) {
     context.dispatch('increment') 
     context.dispatch('increment')
     },
  increment ( context ) {handle_increment()}
}

export default createStore({
  state,
  actions
})

you will get the following results:

A Vuex mutation can be called from:

  • a Vue component using this.$store.commit() (see call from the created method to the increment mutation in the following example)
  • a Vuex action or mutation using the commit attribute of the context that the handler gets from its parameter (see call from incrementtwice to increment in the following example)

Also a mutation can be mapped with a method using the MapMutation api. A callLink is created to the mapped mutation whenever its corresponding method is called. In the following example a callLink is created from the Counter.vue Source Code to the incrementtwice mutation due to the @click=“incrementtwice” in the vue.

Thus when analyzing the following source code:

// index.ts
import { createApp } from 'vue'
import Counter from './Counter.vue'
import store from './store'

const app = createApp(Counter)
app.use(store)
app.mount('#app')
// Counter.vue
<template>
  <div id="app">
    Clicked: {{ $store.state.count }} times, count is {{ evenOrOdd }}.
    <button @click="incrementtwice">+</button>
    <button @click="increment">-</button>
  </div>
</template>

<script lang="ts">
import { mapGetters, mapMutations } from 'vuex'

export default {
  computed: mapGetters([
    'evenOrOdd'
  ]),
  methods: mapMutations([
    'incrementtwice',
    'increment'
  ]),
  
  created(){
     this.$store.commit('increment')
  }
}
</script>
//store.ts

import { createStore } from 'vuex'

// root state object.
// each Vuex instance is just a single state tree.
const state = {
  count: 0
}

const mutations = {
  incrementtwice( context ) {
     context.commit('increment') 
     context.commit('increment')
     },
  increment ( context ) {handle_increment()}
}

// A Vuex instance is created by combining the state, mutations, actions, and getters.
export default createStore({
  state,
  mutations
})

you will get the following results:

A Vuex getter can be called from:

  • a Vue component using this.$store.getters (see call from created to isEven in the following example)
  • a Vuex action or mutation using the getters attribute of the context that the handler gets from its parameter (see call from incrementIfEven to isEven in the following example)
  • another Vuex getter using the second argument of the getter’s handler (see call from evenOrOdd to isEven in the following example)

Also a getter can be mapped with a computed using the MapGetters api. A callLink is created to the mapped getter whenever its corresponding computed is called. In the following example a callLink is created from the Counter.vue Source Code to the evenOrOdd getter.

Thus when analyzing the following source codes:

// index.ts

import { createApp } from 'vue'
import Counter from './Counter.vue'
import store from './store'

const app = createApp(Counter)
app.use(store)
app.mount('#app')
// Counter.vue

<template>
  <div id="app">
    Clicked: {{ $store.state.count }} times, count is {{ evenOrOdd }}. 
    <button @click="increment">+</button>
  </div>
</template>

<script lang="ts">
import { mapGetters } from 'vuex'

export default {
  computed: mapGetters([
    'evenOrOdd'
  ]),

  created(){
    if (this.$store.getters.isEven){
      doSomething()
    }
  }
}
</script>
//store.ts

import { createStore } from 'vuex'

const state = {
  count: 0
}

const mutations = {
  increment (state) {
    state.count++
  },
  decrement (state) {
    state.count--
  }
}

const actions = {
  incrementIfEven ( context ) {
    if (context.getters.isEven) {
      commit('increment')
    }
  }
}

const getters = {
  isEven (state) {return state.count % 2 === 0 ? true : false}
  evenOrOdd(state, getters){
    if (getters.isEven){
      return 'even'}
    else{
      return 'odd'
    }
  }
}

export default createStore({
  state,
  getters,
  actions,
  mutations
})

you will get the following results:

A Pinia action can be called from:

  • a Pinia action in the same store (see call from increment_twice method to increment method in the following example);
  • a Pinia action in a different store, or a general caller by importing its store.

Also an action can be mapped with a method using the mapActions API that its store is the first argument. A callLink is created to the mapped action whenever its corresponding method is called.

In the following example, callLinks are created from the App.vue source code to:

  • the increment action due to the @click=“increment”;
  • the increment_twice action due to the @click=“increment_twice”;
  • the decrement action due to the @click=“decrement”.

Thus when analyzing the following source codes:

// main.ts

import { createApp } from 'vue'
import App from './App.vue'
import { useCounterStore } from './counter';

const app = createApp(App)

app.use(useCounterStore)

app.mount('#app')
// App.vue

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
    <button @click="increment_twice">Increment Twice</button>
    <button @click="decrement">Decrement</button>
  </div>
</template>

<script lang="ts">
import { mapActions } from 'pinia';
import { useCounterStore } from './counter';

export default {
  methods: {
    ...mapActions(useCounterStore, ['increment', 'increment_twice', 'decrement']),
  },
};
</script>
// counter.ts

import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),

  actions: {
    increment() {
      this.count++
    },
    increment_twice() {
      this.increment()
      this.increment()
    },
    decrement() {
      this.count--
    },
  },
});

you will get the following results:

A Pinia getter can be called from:

  • a Pinia getter in the same store (see call from tenfoldCount method to doubleCount function definition in the following example);
  • a Pinia action in the same store (see call from logTenfoldCount method to tenfoldCount method in the following example);
  • a Pinia getter/action in a different store, or a general caller by importing its store.

Also a getter can be mapped with a computed using the mapState API that its store is the first argument. A callLink is created to the mapped getter whenever its corresponding computed is called.

In the following example, callLinks are created from the App.vue source code to:

  • the function of doubleCount getter,
  • the tenfoldCount getter,
  • the logTenfoldCount action.

Thus when analyzing the following source codes:

// main.ts

import { createApp } from 'vue'
import App from './App.vue'
import { useCounterStore } from './counter';

const app = createApp(App)

app.use(useCounterStore)

app.mount('#app')
// App.vue

<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Double Count: {{ doubleCount }}</p>
    <p>Tenfold Count: {{ tenfoldCount }}</p>
    <button @click="logTenfoldCount">Log ten times count</button>
  </div>
</template>

<script lang="ts">
import { mapState, mapActions } from 'pinia';
import { useCounterStore } from './counter';

export default {
  computed: {
    ...mapState(useCounterStore, {
      count: 'count',
      doubleCount: 'doubleCount',
      tenfoldCount: 'tenfoldCount',
    }),
  },

  methods: {
    ...mapActions(useCounterStore, ['logTenfoldCount']),
  },
};
</script>
// counter.ts

import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),

  getters: {
    doubleCount: (state) => state.count * 2,
    tenfoldCount(state, getters) {
      return getters.doubleCount * 5
    }
  },

  actions: {
    logTenfoldCount() {
      const tenTimesCount = this.tenfoldCount;
      console.log(`The tenfold count is: ${tenTimesCount}`);
    },
  },
});

you will get the following results:

Other supported packages from vue ecosystem

vue-property-decorator and vue-facing-decorator

vue-property-decorator and vue-facing-decorator allow defining a vue component, its methods and watchers using decorators. This extension supports the use of @Component, and @Watch decorators. When analyzing the following source code:

// index.ts

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

@Component
export default class MesIcon extends Vue {
   child = "value"
   foomethod(){}
   
   @Watch('child')
   onChildChanged(val: string, oldVal: string) {}
}

This extension is able to find that the foomethod method defines a Vuejs method and that the onChildChanged method watches the child variable. If a call to the identified Vuejs methods and watchers is found within the source code, a callLink will be created.