Typescript in vue - Property 'validate' does not exist on type 'Vue | Element | Vue[] | Element[]'.

Solutions:

Simple:

(this.$refs.form as Vue & { validate: () => boolean }).validate()

Alternative (use this if you reference this.$refs.form multiple times in your component):

computed: {
  form(): Vue & { validate: () => boolean } {
    return this.$refs.form as Vue & { validate: () => boolean }
  }
} // Use it like so: this.form.validate()

Reusable (use this if you use the v-form component multiple times across your application):

// In a TS file
export type VForm = Vue & { validate: () => boolean }

// In component, import `VForm`
computed: {
  form(): VForm {
    return this.$refs.form as VForm
  }
}

Explanation:

In the Vue template syntax, we can use the ref attribute on a Vue instance or a DOM element. If ref is used in a v-for loop, an array of Vue instances or DOM elements is retreived.

This is why this.$refs can either return Vue | Element | Vue[] | Element[].

In order for TypeScript to know which type is being used, we need to cast the value.

We can either do:

(this.$refs.form as Vue).validate() or (<Vue>this.$refs.form).validate()

We cast it to Vue because v-form is a Vue instance (component) and not an Element.

My personal preference is to create a computed property which returns the Vue instance(s) or DOM element(s) already casted.

ie.

computed: {
  form(): Vue {
    return this.$refs.form as Vue
  }
}

The v-form instance has a validate method that returns a boolean, so we need to use an intersection type literal:

computed: {
  form(): Vue & { validate: () => boolean } {
    return this.$refs.form as Vue & { validate: () => boolean }
  }
}

Then we can use it like so: this.form.validate()


A better solution would be to create a type with the intersection so that it can be reused across multiple components.

export type VForm = Vue & { validate: () => boolean }

Then import it in the component:

computed: {
  form(): VForm {
    return this.$refs.form as VForm
  }
}

let form: any = this.$refs.form
if(form.validate){}

If you use vue-class-component with vue-property-decorator you can do it like this:

Define in a types.ts a new Type with the vuetify form functions:

export type VForm = Vue & {
  validate: () => boolean;
  resetValidation: () => boolean;
  reset: () => void;
};

Then import in your component:

import { VForm } from "types";
import { Component, Ref} from "vue-property-decorator";

Use @Ref in your component to define the form:

export default class YourComponent extends Vue {
  @Ref("form") readonly form!: VForm;
}

so in your methods you can use it like this:

this.form.validate();
this.form.resetValidation();
this.form.reset();