What is the proper way to declare static references in the Composition API with Typescript?

Currently, I am using the Composition API (with <script setup lang='ts'>) to create a ref that is utilized in my template:

const searchRef = ref(null)
onMounted(() => { searchRef.value.focus() })

Although it works and my code compiles without any errors, my IDE (either JetBrains Goland or Webstorm) displays a warning with

TS2531: Object is possibly 'null'.
.

The more drastic solution involves using

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Object is possibly 'null'.

However, I'm interested in finding a better approach if possible.

I had initially hoped that utilizing optional chaining would resolve the issue:

const searchRef = ref(null)
onMounted(() => { searchRef.value?.focus() })

Despite still compiling and functioning correctly, this implementation now triggers an error message of

TS2339: Property 'focus' does not exist on type 'never'.

What would be the proper way to tackle this particular dilemma?

Answer №1

When using template refs, it's important to specify a generic type argument for the ref during initialization. The specified generic type should match the type of the targeted element in the template reference.

Below are examples demonstrating how to use template refs with native HTML elements:

const htmlElemRef = ref<HTMLElement>()         // => type: HTMLElement | undefined
const inputRef = ref<HTMLInputElement>()       // => type: HTMLInputElement | undefined
const textareaRef = ref<HTMLTextAreaElement>() // => type: HTMLTextAreaElement | undefined

While initializing with null is optional, omitting it can lead to more concise code. In this case, the resulting type becomes <T | undefined>, which accurately reflects that the ref will be

undefined</code if the targeted element isn't present in the template structure. Optional chaining should still be used when accessing the value of the <code>ref
since it might be undefined.

For example:

const searchRef = ref<HTMLInputElement>()
onMounted(() => { searchRef.value?.focus() })

As mentioned by @Kurt, Vue components require a different approach when working with template refs. For these scenarios, the generic type for the ref should be an InstanceType of the component's type (obtained from a .vue import) (documentation):

InstanceType<typeof MyComponentDefinition>

For instance:

import HelloWorld from '@/components/HelloWorld.vue'

const helloRef = ref<InstanceType<typeof HelloWorld>>()

Please note that if you're working with TypeScript files and Volar instead of Vue Single File Components, make sure to enable Volar's Takeover Mode.

demonstration link

Answer №2

To address this issue, one recommended solution is to manually include the appropriate typings:

const searchElementRef: Ref<HTMLElement | null> = ref(null);
onMounted(() => { searchElementRef.value?.focus() });

Please be aware that the type HTMLElement may vary if the reference is pointing to a Vue Component (e.g.

Ref<HTMLElement | Vue | null>
).

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for utilizing Variant on an overridden component using as props in ChakraUI

I created a custom Component that can be re-rendered as another component using the BoxProps: export function Label ({ children, ...boxProps }: BoxProps) { return ( <Box {...boxProps}> {children} </Box> ); } It functio ...

What could be causing my Page to not update when the Context changes?

In my Base Context, I store essential information like the current logged-in user. I have a User Page that should display this information but fails to re-render when the Context changes. Initially, the Context is empty (isLoaded = false). Once the init fu ...

Step-by-step tutorial: Uploading an image from Vue.js using axios to phpMyAdmin

Within my owner.vue file, the administrators have the privilege to input an owner's information into a table named "owner". Currently, the name of the owner can be successfully added to the database, however, the image column remains empty. My intenti ...

Encountering routing challenges while trying to navigate to the identical component

I have a dashboard specifically for 'x'. When I click on the logo in the header bar, it triggers a function with the following functionality: if(this.isVerifier) { this.$router.push({ name: 'sales-verifier-dashboard', ...

What is the process for removing a specific row from a datatable?

I have implemented a data-table using Vue and Vuetify. When I click on the delete icon in a specific row, a snackbar pops up with two buttons - yes and no. If I click on the yes button, I want to delete that specific row. How can I achieve this functionali ...

Step-by-step guide: Mocking an image using a fixture in Cypress

I'm currently utilizing cypress to run tests on my VueJS application. One issue I am facing involves simulating the display of an image on a page. Specifically, I am trying to load a user profile using the following code snippet: describe('Test ...

Encountering build issues in my next.js application post updating to version 12.#.# and implementing Typescript

In my next.js application, I recently upgraded to version 10 and added TypeScript to the mix. Despite ironing out all issues during development, I encountered errors when running yarn next build due to my use of the keyword interface. ./src/components/ ...

Easiest Angular Carousel Solution

My goal is to create a basic Angular Carousel to enhance my understanding of Angular. While I have received helpful answers in the past, I am seeking further clarification to deepen my knowledge of Angular2+ and Typescript. Here's what I have so far: ...

Angular 8: How to Retrieve Query Parameters from Request URL

Can I retrieve the GET URL Query String Parameters from a specific URL using my Angular Service? For example, let's say I have a URL = "http:localhost/?id=123&name=abc"; or URL = ""; // in my service.ts public myFunction(): Observale<any> ...

How can Vue be used to dynamically alter a string within an input field by incorporating the status of checked checkboxes?

Yesterday, I stumbled upon a concise Vue presentation on YouTube before answering a technical question on Stack Overflow. The question involved generating checkbox elements based on a string of text containing '1's and '0's, with the ch ...

The proper method for updating data on a backend API using Axios and Vue

I am working on a Vue application that includes several form fields. I want to ensure that any changes made by the user are saved in real-time to a backend database using a REST API with Axios, without requiring the user to click a save button. I have two ...

Angular: Unable to access values of non-existent data (reading '0')

I'm encountering an error when trying to import an excel file using the following code Angular Ag Grid Excel Import Cannot read properties of undefined (reading '0') I'm attempting to import a file named Book.csv, and wondering if thi ...

Evaluating Angular/Typescript and its capabilities

I seem to be struggling with the concept of how eval functions in TypeScript/Angular. Can someone provide some guidance on how to make eval work in this scenario? Although the logic may not be perfect in this demo program, I just need help figuring out how ...

Potential explanation for unexpected Typescript initialization error

I am encountering the compiler error The property 'options' is not initialized or assigned in the constructor. However, upon reviewing the code for the respective class, it is clear that this reported error does not accurately reflect the actual ...

Enhance your Next.js application by including the 'style' attribute to an element within an event listener

I am currently trying to add styles to a DOM element in Next.js using TypeScript. However, I keep getting the error message "Property 'style' does not exist on type 'Element'" in Visual Studio Code. I have been unable to find an answer ...

Encountering an error during the installation process of Vue Native using the Vue

I recently created a project called helloworld, following the instructions at However, I encountered an error while trying to start my first application: Unable to resolve "../../App" from "node_modules/expo/AppEntry.js" Here is information about my env ...

Retrieve data from a URL using Angular 6's HTTP POST method

UPDATE: Replaced res.json(data) with res.send(data) I am currently working on a web application using Angular 6 and NodeJS. My goal is to download a file through an HTTP POST request. The process involves sending a request to the server by calling a func ...

Utilizing a GLTF asset as the main Scene element in a Three.js project

I'm struggling with incorporating a gltf model as the main scene in Three.js. Specifically, I have a gltf model of an apartment that I want to load from inside and not outside the apartment. I also need the controls to work seamlessly within the apart ...

Ways to obtain a referrer URL in Angular 4

Seeking a way to obtain the referrer URL in Angular 4. For instance, if my Angular website is example.com and it is visited from another PHP page like domaintwo.com/checkout.php, how can I detect the referring URL (domaintwo.com/checkout.php) on my Angul ...

Angular 6: Issue TS2339 - The attribute 'value' is not recognized on the 'HTMLElement' type

I have a textarea on my website that allows users to submit comments. I want to automatically capture the date and time when the comment is submitted, and then save it in a JSON format along with the added comment: After a comment is submitted, I would li ...