Using vue-class-component: A guide on creating and setting up reactive data

I am currently working with Vue.js using TypeScript and vue-class-component. My goal is to create a custom component with reactive data.

Below is the code I have so far:

<template>
    <div>
        <input v-model="data.name" placeholder="Name">
        <input v-model="data.value" placeholder="Value">
    </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

interface Model {
    name: string;
    value: number;
}
@Component
export default class ClubVue extends Vue {
    private data: Model;

    public mounted() {
        this.data = {...this.$store.getters.data};
    }
}
</script>

In my initial version, an error occurred:

Property or method "data" is not defined on the instance but referenced during render

This is expected because undefined data will not be reactive as mentioned on the vue-class-component page. To solve this, I need to initialize data to null. However, I encountered a TypeScript error:

Property 'data' has no initializer and is not definitely assigned in the constructor

To address this, I attempted to set an initial value of null for data:

private data: Model = null;

Unfortunately, this resulted in another TypeScript error:

Type 'null' is not assignable to type 'Model'

I am hesitant to change the data type to Model | null as I know that data will never be null. Using the non-null assertion operator also didn't work since it made data undefined and therefore non-reactive.

Disabling TypeScript checks entirely is not an ideal solution as they serve a purpose in other parts of the codebase. Is there a proper way to correctly initialize data in this scenario?

Answer №1

One way to define the type for a property like this is as follows:

private data: Model | null = null;

This type can be utilized with type guards in the following manner:

if (this.data) {
  console.log(this.data.name); // Model
}

Alternatively, you can use the non-null assertion operator like so:

console.log(this.data!.name); // Model

If needed, there's a workaround to bypass the typing system using assertion:

private data: Model = null as unknown as Model;

The reason vue-class-component doesn't fully consider TypeScript is because undefined is easier to manage in TypeScript than null, especially due to its ability to signify optional properties.

I am certain that data will never hold a null value.

However, it's important to note that during component initialization, data will indeed be null. This opens up the possibility of an error:

public created() {
    console.log(this.data.name); // potential runtime error, no compilation error
}

public mounted() {
    this.data = {...this.$store.getters.data};
}

Answer №2

If you want to avoid directly assigning data, you can utilize a getter as long as the data is already stored when created. It's important to ensure that your store getters are type-safe!

@Component
export default class ClubVue extends Vue {
    private _data: Model | undefined;

    get data(): Model {
        if (!this._data) {
            this._data = {...this.$store.getters.data};
        }
        return this._data;
    }
}

By using this approach, data will never be undefined because it will either return _data or set _data to the current content of the store and then return that value.
However, if _data is a primitive rather than an object and could evaluate as false (e.g. (Number)0 or (String)""), consider using this._data === undefined instead of !this._data.

You can also simplify the getter function like this:

get data():Model {
    return this._data = this._data || {...this.$store.getters.data};
}

Although this is less explicit, especially for readers who may not be aware that an assignment returns the value being assigned. This can become more confusing with primitive types:

return this._data = 
    this._data === undefined 
        ? {...this.$store.getters.data} 
        : this._data;

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

What are the steps to update your profile picture using Angular?

In my Angular 6 application, I am implementing an image upload feature with the following code: Html: <img [src]="url ? url : 'https://www.w3schools.com/howto/img_avatar.png'"> <br/> <input type='file' (change)="onSelec ...

Typescript for managing the Shopify admin API

Is there anyone who can confirm whether Shopify offers typescript definitions for their admin API? I'm specifically interested in finding types for Orders, Products, and Variants. I initially assumed that this package would have them, but it seems l ...

Can getters and setters be excluded from code coverage reports in Angular projects?

Looking to clean up my coverage reports for the front end portion of an angular project by removing trivial code like getters and setters. I generate my reports using npm run test-sonar -- --coverage, but everything is included in the report when I view ...

What is the proper way to access the current value of a computed property from within its own computation method?

Our goal is to activate a query when a string reaches a length of 3 characters or more, and keep it activated once triggered. Leveraging the Vue 2 Composition API, we have implemented a reactive object to manage the status of queries: import { computed, de ...

What prevents TypeScript from automatically inferring tuple return types in RxJs streams?

When composing an observable stream, the map function infer is a union instead of a tuple. For instance: import { Component } from '@angular/core'; import { from } from 'rxjs'; import { map, tap } from 'rxjs/operators'; expo ...

Creating a fresh type in Typescript based on object keys that are already defined within an interface

Here is the scenario I am currently dealing with: interface ListField { code: number; message: string; } interface List { [key: string]: ListField; } export const allCodes: List = { FIRST: { code: 1, message: 'message 1', }, ...

The system encountered an error when attempting to convert the data '19-10-2002' into a date format

I am trying to pass a date parameter in the format (dd-MM-yyyy) and then convert it into the format (yyyy-MM-dd) before sending it via API. Here is my code: convert(date:string){ date //is in the format(dd-MM-yyyy) date = formatDate(date , " ...

Error in Vue: Expected object but received a function instead of a valid value

I am attempting to apply a computed function to my style. However, the computed function uses a property within it and Vue is throwing an error stating that it expects an object but is receiving a function. Below is the code in question. <template> ...

When faced with the error message "Typescript property does not exist on union type" it becomes difficult to assess the variable

This question is a continuation of the previous discussion on Typescript property does not exist on union type. One solution suggested was to utilize the in operator to evaluate objects within the union. Here's an example: type Obj1 = { message: stri ...

What causes the undefined value of "this" in the Vue Composition API setup function?

A Vue component I've created is using v3's composition API: <template> <input type="checkbox" v-model="playing" id="playing" @input="$emit('play', $event.target.value)" /> <labe ...

Error: Vuex commit fails due to JSON circular structure issue

Using Vue.js along with the vuex store, I make an API call to validate an item, which returns arrays of errors and warnings. Below is my vuex action : export function validateitemReview ({ commit, dispatch, state }, { reviewId, type, itemreviewData }) { ...

How can you utilize Angular Signals in combination with HostBinding to dynamically update styles?

Within a component called app-test, the following code is present: @Input({ transform: booleanAttribute }) reverse: boolean = false; @HostBinding('style.flex-direction') direction: string = this.reverse ? 'column-reverse' : &ap ...

Navigating with Angular: Every time I refresh the page or enter a specific URL, Angular automatically redirects to the parent route

In my CRM module, I have created a custom Routing Module like this: const routes: Routes = [ { path: 'crm', component: CrmComponent, children: [ { path: '', redirectTo: 'companies', pathMatch: 'full&ap ...

Troubleshooting: Angular 6 Renderer2 Issue with Generating Dynamic DOM Elements for SELECT-Option

Currently, I am attempting to dynamically create a select option using Renderer2. Unfortunately, I am facing difficulties in creating the <Select></Select> element, but I can confirm that the <options> are being successfully created. Due ...

Unable to locate module: Issue: Unable to locate '@angular/cdk/tree' or '@angular/material/tree'

Currently utilizing Angular 5 and attempting to create a tree view that resembles a table layout. https://stackblitz.com/edit/angular-hhkrr1?file=main.ts Encountering errors while trying to import: import {NestedTreeControl} from '@angular/cdk/tree ...

Guide to implementing controllers in vuejs2

Hey there, I recently started using vuejs2 with a project that is based on laravel backend. In my vuejs2 project, I wrote the following code in the file routes.js export default new VueRouter({ routes: [{ path: '/test', component: ...

ERROR: The use of @xenova/transformers for importing requires ESM

When working with my Node.js application, I usually start by importing the necessary modules like this: import { AutoModel, AutoTokenizer } from '@xenova/transformers'; Afterwards, I utilize them in my code as shown below: const tokenizer = awai ...

What is the process for incorporating buttons into an Angular mat-table?

I have successfully utilized Angular mat-table to showcase data retrieved from a database: view the image description here <table mat-table [dataSource]="UserDataSourceFilters" class="mat-elevation-z1 mt-5"> <ng-co ...

Is it possible to implement navigation guards with file boot in Quasar framework?

Recently, I created a registration app to test login, register, and navigation guards. However, I am facing an issue where I can always open the link. Below are the codes that I have used: const routes = [ { path: '/', component: () ...

Checking the formik field with an array of objects through Yup for validation

Here is a snippet of the code I'm working on: https://codesandbox.io/s/busy-bose-4qhoh?file=/src/App.tsx I am currently in the process of creating a form that will accept an array of objects called Criterion, which are of a specific type: export inte ...