Vuejs typescript this.$refs.<refField>.value does not exist

JavascriptTypescriptvue.jsVuejs2Vue Component

Javascript Problem Overview


While rewriting my VueJs project in typescript, I came across a TypeScript error.

This is a part of the component that has a custom v-model.

An input field in the html has a ref called 'plate' and I want to access the value of that. The @input on that field calls the update method written below.

Typescript is complaining that value does not exist on plate.

@Prop() value: any;

update() {
    this.$emit('input',
        plate: this.$refs.plate.value
    });
}

template:

<template>  
<div>
    <div class="form-group">
        <label for="inputPlate" class="col-sm-2 control-label">Plate</label>
                 
        <div class="col-sm-10">
            <input type="text" class="form-control" id="inputPlate" ref="plate" :value="value.plate" @input="update">
        </div>
    </div>
    
</div>
</template>

Javascript Solutions


Solution 1 - Javascript

You can do this:

class YourComponent extends Vue {
  $refs!: {
    checkboxElement: HTMLFormElement
  }

  someMethod () {
    this.$refs.checkboxElement.checked
  }
}

From this issue: https://github.com/vuejs/vue-class-component/issues/94

Solution 2 - Javascript

Edit - 2021-03 (Composition API)

Updating this answer because Vue 3 (or the composition API plugin if you're using Vue 2) has some new functions.

<template>
  <div ref="root">This is a root element</div>
</template>

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

  export default defineComponent({
    setup() {
      const root = ref(null)

      onMounted(() => {
        // the DOM element will be assigned to the ref after initial render
        console.log(root.value) // <div>This is a root element</div>
      })

      return {
        root
      }
    }
  })
</script>

Edit - 2020-04:

The vue-property-decorator library provides @Ref which I recommend instead of my original answer.

import { Vue, Component, Ref } from 'vue-property-decorator'

import AnotherComponent from '@/path/to/another-component.vue'

@Component
export default class YourComponent extends Vue {
  @Ref() readonly anotherComponent!: AnotherComponent
  @Ref('aButton') readonly button!: HTMLButtonElement
}

Original Answer

None of the above answers worked for what I was trying to do. Adding the following $refs property wound up fixing it and seemed to restore the expected properties. I found the solution linked on this github post.

class YourComponent extends Vue {
  $refs!: {
    vue: Vue,
    element: HTMLInputElement,
    vues: Vue[],
    elements: HTMLInputElement[]
  }

  someMethod () {
    this.$refs.<element>.<attribute>
  }
}

Solution 3 - Javascript

This worked for me: use (this.$refs.<refField> as any).value or (this.$refs.['refField'] as any).value

Solution 4 - Javascript

son.vue

const Son = Vue.extend({
  components: {},
  props: {},
  methods: {
    help(){}
  }
  ...
})
export type SonRef = InstanceType<typeof Son>;
export default Son;

parent.vue

<son ref="son" />

computed: {
  son(): SonRef {
    return this.$refs.son as SonRef;
  }
}

//use
this.son.help();

Solution 5 - Javascript

Avoid using bracket < > to typecast because it will conflict with JSX.

Try this instead

update() {
    const plateElement = this.$refs.plate as HTMLInputElement
    this.$emit('input', { plate: plateElement.value });
}

as a note that I always keep remembering > Typescript is just Javascript with strong typing capability to ensure type safety. So (usually) it doesn't predict the type of X (var, param, etc) neither automatically typecasted any operation.

Also, another purpose of the typescript is to make JS code became clearer/readable, so always define the type whenever is possible.

Solution 6 - Javascript

Maybe it will be useful to someone. It looks more beautiful and remains type support.

HTML:

<input ref="inputComment" v-model="inputComment">

TS:

const inputValue = ((this.$refs.inputComment as Vue).$el as HTMLInputElement).value;

Solution 7 - Javascript

In case of custom component method call,

we can typecast that component name, so it's easy to refer to that method.

e.g.

(this.$refs.annotator as AnnotatorComponent).saveObjects();

where AnnotatorComponent is class based vue component as below.

@Component
export default class AnnotatorComponent extends Vue {
    public saveObjects() {
        // Custom code
    }
}

Solution 8 - Javascript

I found a way to make it work but it is ugly in my opinion.

Feel free to give other/better suggestions.

update() {
    this.$emit('input', {
        plate: (<any>this.$refs.plate).value,
    });
}

Solution 9 - Javascript

Make sure to wrap your exports with Vue.extend() if you are converting your existing vue project from js to ts and want to keep the old format.

Before:

enter image description here

<script lang="ts">

export default {
  mounted() {
    let element = this.$refs.graph;

...

After:

enter image description here

<script lang="ts">

import Vue from "vue";

export default Vue.extend({
  mounted() {
    let element = this.$refs.graph;

...

Solution 10 - Javascript

With Vue 3 and the Options API, this is what worked for me:

<script lang="ts">
import {defineComponent} from 'vue';

export default defineComponent({
  methods: {
    someAction() {
      (this.$refs.foo as HTMLInputElement).value = 'abc';
    },
  },
});
</script>

The autocomplete doesn't bring the foo property from $refs because it's defined in the template, and apparently there's no information inferred from it.

However, once you force the casting of .foo to the HTML element type, everything works from there on, so you can access any element property (like .value, in the example above).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRickView Question on Stackoverflow
Solution 1 - JavascriptGeorgeView Answer on Stackoverflow
Solution 2 - JavascriptJohn SnowView Answer on Stackoverflow
Solution 3 - Javascriptuser3377090View Answer on Stackoverflow
Solution 4 - JavascriptbestRenektonView Answer on Stackoverflow
Solution 5 - JavascriptDrSensorView Answer on Stackoverflow
Solution 6 - JavascriptСемён ПлевакоView Answer on Stackoverflow
Solution 7 - JavascriptAnonymous CreatorView Answer on Stackoverflow
Solution 8 - JavascriptRickView Answer on Stackoverflow
Solution 9 - JavascriptJossef Harush KadouriView Answer on Stackoverflow
Solution 10 - JavascriptrodrigocfdView Answer on Stackoverflow