I am struggling to grasp the concept of ref unwrapping within a TypeScript template

I'm currently in the process of converting some Vue3 code from javascript to typescript, and I am struggling to comprehend the unwrapping of a ref/computed value in the template.
I used to believe that the template would automatically unwrap reactive properties, but it appears that this is no longer the case.

Here is the code snippet:

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

class BaseBlock {
  style = ref('color: black')
}

interface IRefBlockKey {
  [key: string]: BaseBlock;
}

let Block = new BaseBlock();
let refBlock = ref(new BaseBlock());
let refWithKeyBlock = ref({ myBlock: new BaseBlock() });
let refWithInterface = ref<IRefBlockKey>({ myBlock: new BaseBlock() });
</script>

<template>
  <div :style="Block.style">Error in IDE</div>
  <div :style="Block.style.value">No Error</div>
  <div :style="refBlock.style">No Error</div>
  <div :style="refWithKeyBlock['myBlock'].style">No Error (ok...?)</div>
  <div :style="refWithInterface['myBlock'].style">Error in IDE (why now!!)</div>
</template>

The first and last div are both causing an error in my IDE

Type 'Ref<string>' is not assignable to type 'StyleValue | undefined'.
.
The fact that the first div isn't working has left me feeling disoriented, but the issue with the last one is really puzzling.

Can anyone provide guidance on understanding what exactly is happening here?

Answer №1

SOLUTION

There are several approaches to solving this issue.

The optimal solution:

Rewrite the code using composables instead of classes. Here is how you can refactor the code:

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

function useBaseBlock() {
  style = ref<string>('color: black')
  return { style }
}

type IRefBlockKey = {
  [key: string]: {style: Ref<string> | string};
}

let refWithInterface = ref<IRefBlockKey>({ myBlock: useBaseBlock()});
</script>

<template>
  <div :style="refWithInterface['myBlock'].style">Updated code here</div>
</template>

Note that the type has been changed to Ref<string> | string. If you prefer using reactive instead of ref, simply using string will suffice.

The less preferable option

You can use unref to access the value of

refWithInterface['myBlock'].style
:
unref(refWithInterface['myBlock'].style)
While this method works, it is not the most ideal solution.

The unconventional choice:

The style attribute supports CSSProperty (a variant of it depending on the element), as well as string and undefined types. You could potentially define your own type such as Ref<string> for better IDE support, but this workaround is not recommended, so it's best to avoid it!

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

Incorporate an interface for handling potential null values using Typescript

Currently, I am utilizing Express, Typescript, and the MongoDB Node.js driver to develop my API. However, I am encountering an issue with the findOne method as it returns a promise that resolves with either an object containing the first document matching ...

Encountered a hiccup during the installation of ssh2-sftp-client on Next.js

I'm looking for a way to save uploaded files in my domain's storage using SFTP. I came across the multer-sftp package, but when I attempted to run the command yarn add multer-sftp ssh2-sftp-client, I encountered a strange error with the second pa ...

I am attempting to utilize the fetch API method to initialize the store's state, but for some reason, it is not functioning properly

Within my store.js file, I have a state called user_data, with its initial method set to fetch_user_data: export default new Vuex.Store({ state: { user_data: util.fetch_user_data('username') ... } located in the util.js file: util. ...

Typescript compiles only the files that are currently open in Visual Studio

In my Visual Studio Typescript project, I am in the process of transforming a large library of legacy JavaScript files by renaming them to *.ts and adding type information to enhance application safety. With over 200 files to modify, it's quite a task ...

Converting an Angular1 App into a VueJs app: A step-by-step guide

Let's dive right in: I'm embarking on the journey of revamping an app that originally utilized Angular 1, but this time around I'll be harnessing the power of VueJS 2. As someone unfamiliar with Angular 1, I'm faced with some perplexing ...

Expanding Material UI functionality across various packages within a monorepository

Currently, I am using lerna to develop multiple UI packages. In my project, I am enhancing @material-ui/styles within package a by incorporating additional palette and typography definitions. Although I have successfully integrated the new types in packag ...

Utilizing a function upon page initialization in VueX

I am currently learning Vue with Vuex and I have created a method called 'llamarJson' which is used to retrieve JSON data. However, I am facing difficulties in using this method when the page loads. I have tried various approaches but have not be ...

Adding a line break in a Buefy tooltip

I am trying to show a tooltip with multiple lines of text, but using \r\n or is not working. <b-tooltip label="Item 1 \r\n Item 2 \r\n Item 3" size="is-small" type="is-light" position="is-top" animated multilined> ...

"Encountered a 'Module not found: Error: Can't resolve' issue while attempting to install from GitHub. However, the standard installation process

I am currently utilizing the Quilljs JavaScript library for a project in Angular. After installing it with the following command: npm install --save quill Everything appears to be functioning correctly, and I am able to import the Quill class into my Ty ...

How to simulate a particular class from a node package using Jest mocks

In my project, I'm looking to specifically mock the Socket class from the net node module. The documentation for this can be found here. Within my codebase, there is a class structured similar to the following... import { Socket } from 'net&apo ...

Step-by-step guide for resolving the issue of "Observable.share is not recognized as a function" in Angular 2

When working with cache structure in Ionic 2, I often encounter an error when defining an observable array to store data retrieved from the server. How can I troubleshoot this issue and resolve it? marketArray : Observable<any>; /* GLOBAL */ th ...

"Enhancing the functionality of @angular/fire by transitioning from version 6.x to 7.x

I need to update my app dependencies and code from @angular/fire 6.x to 7.1.0-rc4 in order to access a feature that is not available in the 7.0.x version. I made the necessary changes in my package.json as follows: "@angular/fire": "~7.1.0-r ...

I'm curious if there is an eslint rule specifically designed to identify and flag any unnecessary spaces between a block comment and the function or

Can anyone help me find a solution to prevent the following issue: /** * This is a comment */ function foo() { ... } I need it to be corrected and formatted like this: /** * This is a comment */ function foo() { ... } ...

The TypeScript compiler is tolerant when a subclass inherits a mixin abstract class without implementing all its getters

Update: In response to the feedback from @artur-grzesiak below, we have made changes to the playground to simplify it. We removed a poorly named interface method and now expect the compiler to throw an error for the unimplemented getInterface. However, the ...

Issue with Typescript - Node.js + Ionic mobile app's Angular AoT build has encountered an error

Currently, I am in the process of developing an Android application using Node.js and Ionic framework. The app is designed to display random text and images stored in separate arrays. While testing the app on Chrome, everything works perfectly fine. Upon ...

How does one distinguish between the uses of "any" and "any[ ]"?

Exploring the Difference Between any and any[ ] An Illustrative Example (Functioning as Expected) variable1: any; variable2: any[]; this.variable1 = this.variable2; Another Example (Also Functioning as Intended) variable1: any; v ...

Is there a method available that functions akin to document.getelementbyid() in this specific scenario?

Currently, I am tackling a project that involves implementing a search function. My initial step is to ensure that all input is converted to lowercase in order to simplify SQL calls. However, I have encountered a challenge that is proving difficult for me ...

What are the limitations of using concatMap for handling multiple requests simultaneously?

In my current function, I am receiving an array of objects called data/ids as a parameter. Within this function, I need to execute a post request for each element/id: fillProfile(users) { const requests = []; console.log( 'USERS.length:&apos ...

Issue with authentication and cross-origin resource sharing (CORS) when implementing Spring Boot, Spring Security, Vue.js,

Running on vue.js 3, Vite 4.0.2, axios 0.25.0, and spring boot (Starter 2.7.2). A backend has been created in spring boot while using vue.js3, vite, and axios for the UI. Now, I simply want to make a call to rest with axios. Before implementing these func ...

What about a toggle for read-only TypeScript everywhere? (parameters in functions)

Is there a method, whether through a macro library, an eslint rule, a tsconfig setting, a special global.d.ts file, or some other means, to automatically set function arguments as readonly by default? // I wish for the compiler to transform this: functio ...