Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define type for ref(binding on template) In Vue3, using TypeScript?

Template:

<tremplate>
  <div ref="element"></div>
</template>

Script:

export default {
  setup() {
    const element = ref(null);
    return {
      element,
    };
  },
};

This is a normal way to define a ref in vue3, but in JavaScript way. And if I'm using TypeScript, I will need to define a type for value element, right?

How do I do to ensure the correct type for value element?

like image 427
Shook Lyngs Avatar asked Nov 25 '20 09:11

Shook Lyngs


People also ask

Does vue2 support TypeScript?

TypeScript also improves developer ergonomics via type-based auto-completion in IDEs. Vue is written in TypeScript itself and provides first-class TypeScript support. All official Vue packages come with bundled type declarations that should work out-of-the-box.

How do you use REF in Vue 2?

Referencing DOM Elements in Vue # Vue can store references to DOM elements in a property called $ref . The first thing we have to do, is add a ref attribute to the element we want to reference in our Javascript. The value of the ref attribute will be the name of it within the $ref property.

What is ref in vue3?

ref is a special attribute, similar to the key attribute discussed in the v-for chapter. It allows us to obtain a direct reference to a specific DOM element or child component instance after it's mounted.

Does Vue 3 support TypeScript?

Now, you should be able to get your Vue app up and running in TypeScript with features like defineComponent , data, props, computed properties, methods, and watchers. Vue 3.0 includes better support for TypeScript out of the box, and the entire Vue code was rewritten in TypeScript to improve maintainability.


4 Answers

Well, that would depend on whether or not you need it typed and to provide member information (public properties, methods, etc). If you do, then yes you need to define a type for it; otherwise, you don't have to, and can simply access the unwrapped reference with .value which leaves it as type any (I bet you figured out this one).

But if you have to, you need to tell the compiler what it is or what it's going to be assigned on. To do that, you'll want to use the third overload of ref (with no argument) and explicitly set the generic type to the desired type—in your case, you want HTMLDivElement (or simply HTMLElement if you don't care about the specific members it has to offer).

export default defineComponent({
  setup() {
    const el = ref<HTMLDivElement>();

    onMounted(() => {
      el.value // DIV element
    });

    return {
      el
    }
  }
})

In JavaScript, you don't have type checking, so passing null on the ref function is as good as not passing anything (which is especially okay for template refs)*; it could even come across as being misleading in a sense that the unwrapped value actually resolves to something else but null.

* When using the Composition API, the concept of "reactive refs" and "template refs" are unified. And the reason we're accessing this particular type of ref on the mounted hook is because the DOM element will be assigned to it after initial render.

References:

  • https://v3.vuejs.org/guide/composition-api-template-refs.html#template-refs
like image 160
Yom T. Avatar answered Oct 26 '22 18:10

Yom T.


The line isn't correct:

    const el = ref<HTMLDivElement>();

The el is not an HTMLDivElement. Instead, it's a proxy to the element. The $el of that proxy is the actual HTMLDivElement. Though I'm not sure if I get it right. In a component, I managed to type it as follow:

import { ComponentPublicInstance, defineComponent, ref } from 'vue';

export default defineComponent({
  // snipped...
  setup() {
    const field = ref<ComponentPublicInstance<HTMLInputElement>>();
    return {
      field,
      fun() { field.value.$el.value = 'some value'; }
    };
  }
  // snipped...
});
like image 28
eidng8 Avatar answered Oct 26 '22 17:10

eidng8


<template>
   <ChildComponent ref="childRef">
</template>
<script lang="ts" setup>
import ChildComponent from './ChildComponent.vue'
import { ref } from 'vue'

const childRef = ref<InstanceType<typeof ChildComponent>>()
childRef.value.childMethods()

</script>

like image 30
李文雄 Avatar answered Oct 26 '22 17:10

李文雄


Vue 3.2+

<template>
   <input ref="fileInput" style="display: none;" type="file" @change="onFileSelected" />
   <button @click="fileInput?.click()">Pick Files</button>
</template>

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

const fileInput = ref<HTMLDivElement>()

function onFileSelected(event: any) { console.log("Event: " + event) }
</script>

Second example

<template>
   <div ref="coolDiv">Some text</div>
   <button @click="changeCoolDiv">Pick Files</button>
</template>

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

const coolDiv = ref<HTMLDivElement>()

function changeCoolDiv() {
  if(coolDiv) {
    coolDiv.value // Div element
  }
}
</script>
like image 24
Mises Avatar answered Oct 26 '22 16:10

Mises