Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue3 Typescript - property does not exist on type issue

I am trying to fill up a component with leads coming from an API. I have a LeadService file as well as my vue template file. The issue I'm having, is I'm using an async call on my template file which works, but when I go to compute the values it throws a property does not exist on type error. It actually works you can see the correct components behind the error message. I can't figure out how to make the error go away.

Here's the service class LeadService.ts

import ApiService from "@/core/services/ApiService";

interface Lead {
  id: string;
  first_name: string;
  last_name: string;
  lead_form_name: string;
  email: string;
  campaign: string;
  timestamp: number;
  mobile_number: string;
  message: string;
  medium: string;
  city: string;
  state: string;
  leadType: string;
  quality: string;
  source: string;
  call_link: string;
  company: string;
  country: string;
}

export default class LeadService {

  getLeads() {

    const accountInfo = JSON.parse(localStorage.getItem('accountInfo') || '{}');

    ApiService.setHeader();

    return ApiService.query("/leads", {params: {client_id : accountInfo.client_id}})
      .then(({ data }) => {
        let leadData: Lead[] = data['Items'];
        return leadData;
      })
      .catch(({ response }) => {
        return response;
      });

  }
}

Here is my vue template Leads.vue

<template>
  <!--begin::Leads-->
  <div class="row gy-5 g-xl-8 mb-8">
    <div class="col-xxl-12">
      <LeadTracker
        :lead-data="leadData"
        :updateQuality="updateQuality"
        :key="componentKey"
      />
    </div>
  </div>

  <div class="row gy-5 gx-xl-8 mb-8">
    <div class="col-xxl-8">
      <LeadMethods
        chart-height="500"
        :method-data="getLeadMethods"
      ></LeadMethods>
    </div>
  </div>
  <!--end::Leads-->
</template>

<script lang="ts">
import { defineComponent, onMounted } from "vue";
import { setCurrentPageTitle } from "@/core/helpers/breadcrumb";
import LeadMethods from "@/components/leads/methods/LeadMethods.vue";
import LeadTracker from "@/components/leads/tracker/LeadTracker.vue";
import LeadService from "@/core/services/LeadService";
import ApiService from "@/core/services/ApiService";

export default defineComponent({
  name: "leads",
  components: {
    LeadMethods,
    LeadTracker,
  },
  data() {
    return {
      leadData: {},
    }
  },
  beforeMount: async function() {
    this.leadData = await new LeadService().getLeads()
  },
  setup() {
    onMounted(() => {
      setCurrentPageTitle("Lead Activity");
    });

    const sourceThreshold = 5;

    return {
      sourceThreshold,
      componentKey: 0
    };
  },
  computed: {
    getLeadMethods(): object {
      const leadMethods: Array<object> = [];
      const totalLeads = this.leadData.length;

      console.log('called getLeadMethods check this.leadData', this.leadData);

      // Get the total number of Paid Media leads
      const totalPaid = this.leadData.filter(
        lead => lead.medium == "paid_media"
      ).length;

      // Get the total number of Calls
      const totalCall = this.leadData.filter(lead => lead.leadType == "call")
        .length;

      // Separate form leads from the rest
      const formData = this.leadData.filter(lead => lead.leadType == "form");

      // Make array for form names
      const formTypes: Array<string> = [];
      this.leadData.filter(lead => {
        if (!formTypes.includes(lead.lead_form_name))
          formTypes.push(lead.lead_form_name);
      });

      // Create objects for each form by name, push to leadMethods
      formTypes.filter(type => {
        let totalFormLeads = 1;
        formData.filter(form => {
          if (form.lead_form_name == type) totalFormLeads++;
        });
        const formMethod = {
          name: type,
          description: "Lorem ipsum dolor sit amet, consectetur.",
          total: totalFormLeads,
          percent: Math.round((totalFormLeads / totalLeads) * 100)
        };
        leadMethods.push(formMethod);
      });

      const callTracking = {
        name: "Location Based Call-Tracking",
        description: "Lorem ipsum dolor sit amet, consectetur.",
        total: totalCall,
        percent: Math.round((totalCall / totalLeads) * 100)
      };
      const paidSearch = {
        name: "Paid Search",
        description: "Lorem ipsum dolor sit amet, consectetur.",
        total: totalPaid,
        percent: Math.round((totalPaid / totalLeads) * 100)
      };

      leadMethods.push(callTracking, paidSearch);

      return leadMethods;
    }
  }
});
</script>

The problem begins in my computed functions, where I start filtering this.LeadData Essentially every filter throws a Property does not exist on type error, but they do exist.

It's important to note, that when this.leadData gets set, it is a Proxy. Any help would be appreciated, I was wondering if I could just suppress the error although I don't like that solution.

For instance, in my first filter in the computed methods

// Get the total number of Paid Media leads
      const totalPaid = this.leadData.filter(
        lead => lead.medium == "paid_media"
      ).length;

medium is a property of leadData and I can actually console log it and it works just fine, but it still always throws the property does not exist on type.

like image 202
John David Avatar asked Oct 19 '25 05:10

John David


1 Answers

The type of leadData is inferred from its declaration in data(). It's initialized to {}, which means its type is an immutable empty object (and no properties can be attached to it). However, leadData is eventually assigned the return of LeadService().getLeads(), so its type should actually be an array of Lead objects.

To properly type leadData, initialize it to an empty array with a type assertion of Lead[]:

export default defineComponent({
  data() {
    return {
      //leadData: {}, ❌
      leadData: [] as Lead[], ✅
    }
  }
})
like image 139
tony19 Avatar answered Oct 21 '25 20:10

tony19



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!