Vuejs typescript this.$refs.<refField>.value does not exist
Solution 1
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
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
This worked for me: use
(this.$refs.<refField> as any).value
or (this.$refs.['refField'] as any).value
Solution 4
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
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.
Rick
Passionate and enthusiastic software developer. Most interested in c# and angular.
Updated on July 24, 2022Comments
-
Rick almost 2 years
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>
-
pranavjindal999 about 6 yearsI'm using
let mycomp = Vue.extend({})
syntax. How can I do the same in that? Also should I use the above syntax? -
George about 6 yearsYou could create an interface that represents the type of refs, and then cast to that. At least then you're avoiding the any, and your view will be type checked against it.
-
pranavjindal999 about 6 yearsI'd need to cast everytime i want to use that ref or can I somehow write it once?
-
George about 6 yearsThis is generally why people use vue-class-component: classes are better suited to defining types than objects as with objects it's harder (still possible I believe) to specify component-wide types.
-
pranavjindal999 about 6 yearsHmm thanks.. I actually hate decorators in vue class components.
-
George about 6 yearsAny particular reason why? This problem wouldn't require a decorator - you'd just need to put the component decorator on the class and then declare a variable $refs of your interface type.
-
ffxsam almost 6 yearsThis doesn't work. Maybe it used to, but not today (using vue-cli 3).
-
George almost 5 yearsCasting to any isn't type safe - better to define $refs like in the answer below :)
-
Jens over 4 yearsshould be
(this.$refs['refField'] as any).value
-
walnut_salami over 4 yearsI needed to write
$refs!:
(notice the exclamation mark) in order for it to work, but I'm usingvue-property-decorator
. @George could you please edit the answer if my fix is ok? Don't wanna break it for class component users as maybe there's some difference there (EDIT: ah actually the exclamation mark is in the link you posted) -
John Snow about 4 yearsThis clears the error but defeats the benefits of using typescript in the first place.
-
AverageHelper over 3 yearsIt may be more appropriate to cast to
unknown
, and then cast or type-guard to whatever else you need.unknown
is more permissive, but still does the usual type checks, and is therefore much more safe. -
UndeadKernel about 3 yearsFantastic way to reference the types of custom components. This way also allows me to avoid using the class decorators.
-
d9k about 3 yearslooks cool but methods names autocomplete doesn't work for me in PhpStorm :(
import VForm from 'vuetify/src/components/VForm/VForm.ts'; type RefVForm = InstanceType<typeof VForm>;
-
user2471801 about 3 yearsThis lead me to the right direction. I'm new to vuejs, and don't quite understand the $ref usage, so for others like myself:
@Ref('aButton') readonly button!: HTMLButtonElement
allows you to access the element where<button ref="aButton" ... />
from within your script asthis.button
. -
Vitor Braga about 3 yearsInstanceType<typeof Son> is what I needed. Thanks
-
Andrew Koster almost 3 yearsThere's no need to cast anything. A
ref
is of typeVue | Element | Vue[] | Element[]
, and if that's not specific enough, you can use theinstanceof
operator to fix type errors and throw exceptions or run loops or whatever else you need to do based on the specific return type at runtime. -
ortonomy over 2 yearsYES! this is exactly what is missing from the official docs. Why would I want to use a class component? The options API is much better...
-
Rudey over 2 years
const root = ref(null)
How can the TypeScript compiler possibly know what the type ofroot
is here? Don't you have to specify the type (HTMLDivElement
) explicitly? -
John Snow over 2 yearsYes, I believe that vue's composition api is typed such that ref(null) is really ref<HtmlElement|null>(null) or something like that
-
Mithsew about 2 yearsin case of using options API with defineComponent it is necessary to use
as typeof Component
-
Joe Maffei almost 2 yearsThis approach gave me an error:
Property '$refs' will overwrite the base property in 'BasePublicView... If this is intentional, add an initializer. Otherwise, add a 'declare' modifier or remove the redundant declaration.
. Changing it todeclare $refs: {
fixed it.