Search code examples
javascripttypescriptvue.jspinia

typescript typing error while catching data from pinia state to the template


I'm trying to send data from the Pinia store to a child component's input field, using TypeScript. But I'm having the type error -

Property 'storeForm' does not exist on type '{ $: ComponentInternalInstance; $data: {}; $props: Partial<{}> & Omit<Readonly<ExtractPropTypes<{}>> & VNodeProps & AllowedComponentProps & ComponentCustomProps, never>; ... 10 more ...; $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (args_0: R, args_1: R) => ...'.

Does is mean I need to type the store or other properties?

// Child component

<template>
  <v-sheet width="300" class="mx-auto">
      <v-form fast-fail @submit.prevent>
        <!-- v-model="firstName" -->
        <v-text-field
          label="First name"
          :rules="firstNameRules"
          placeholder="Your Name"
        >{{ storeForm.firstName }}</v-text-field>  // the error goes this line
  
        <!-- v-model="lastName" -->
        <v-text-field
          label="Last name"
          :rules="lastNameRules"
        >{{ storeForm.lastName }}</v-text-field>
  
        <v-btn type="submit" block class="mt-2" @click="submit($event)">Submit</v-btn>
      </v-form>
    </v-sheet>
  </template>
<script lang="ts">
  import { ref } from 'vue'
  import {useForm} from '@/stores/form'
  import  router  from '../router'
  import { defineComponent } from 'vue'


  // export default {

  export default defineComponent({
  setup() {
    const storeForm = useForm();               // getting the Store
    const firstName = ref<string>('')
    const lastName = ref<string>('')
    const firstNameRules = ref<any>(
      (value: String)  => {
        if (value?.length > 3) return true
        return 'First name must be at least 3 characters.'
      }
    )
    const lastNameRules = ref<any>(
      (value: String) => {
          if (/[^0-9]/.test(String(value))) return true
          return 'Last name can not contain digits.'
        }
        )
        
        const submit = (event: Event) => {
          event.preventDefault();
          let user = {
            firstName: firstName.value,
            lastName: lastName.value,
          }
          storeForm.login(user)
          
          router.push('/');
          
          firstName.value = '';
          lastName.value = '';
        }
        return {firstName, lastName, firstNameRules, lastNameRules, submit};
  }
})
</script>

// Store file

import { defineStore } from 'pinia'

export const useForm = defineStore('login',{
  state: () => ({
    firstName: <string>'',             // defining the input string
    lastName: <string>''
  }),
  getters: {
  },
  actions: {
    login(data: any) {
      this.firstName = data.firstName
      this.lastName = data.lastName
    }
  }
})

Solution

  • You are not returning the "storeForm" object from your setup function.

    Recommendations: to make your data reactive you should use the following syntax, as docs suggest.

    https://pinia.vuejs.org/core-concepts/

    <script setup>
    import { storeToRefs } from 'pinia'
    
    const store = useCounterStore()
    // `name` and `doubleCount` are reactive refs
    // This will also extract refs for properties added by plugins
    // but skip any action or non reactive (non ref/reactive) property
    const { name, doubleCount } = storeToRefs(store)
    // the increment action can just be destructured
    const { increment } = store
    </script>