Búsqueda de sitios web

vue.js - Vue3 Typescript - el problema de que la propiedad no existe en el tipo


Estoy intentando llenar un componente con leads provenientes de una API. Tengo un archivo LeadService así como mi archivo de plantilla de Vue. El problema que tengo es que estoy usando una llamada async en mi archivo de plantilla, lo cual funciona, pero cuando intento calcular los valores me lanza un error property does not exist on type. En realidad funciona, puedes ver los componentes correctos detrás del mensaje de error. No puedo averiguar cómo hacer que el error desaparezca.

Aquí está la clase de servicio 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;
      });

  }
}

Aquí está mi plantilla vue 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>

El problema comienza en mis funciones computadas, donde empiezo a filtrar this.LeadData. Esencialmente, cada filtro lanza un error de La propiedad no existe en el tipo, pero sí existen.

Es importante notar que, cuando this.leadData se establece, es un Proxy. Cualquier ayuda sería apreciada, me preguntaba si podría simplemente suprimir el error aunque no me gusta esa solución.

Por ejemplo, en mi primer filtro en los métodos computados

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

medium es una propiedad de leadData y en realidad puedo hacer un console log de ella y funciona perfectamente, pero todavía siempre lanza el property does not exist on type.

Respuesta #1

El tipo de leadData se infiere a partir de su declaración en data(). Se inicializa con {}, lo que significa que su tipo es un objeto vacío inmutable (y no se le pueden agregar propiedades). Sin embargo, leadData finalmente se asigna con el retorno de LeadService().getLeads(), por lo que su tipo en realidad debería ser un arreglo de objetos Lead.

Para escribir correctamente leadData, inicialízalo como un arreglo vacío con una afirmación de tipo de Lead[]:

export default defineComponent({
  data() {
    return {
      //leadData: {}, ❌
      leadData: [] as Lead[], ✅
    }
  }
})

Artículos relacionados