Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js 3: props type validation with custom type

I am developing a single page application using Vue.js 3 and Typescript.

The problem affects a view and a single file component. People.vue retrieves data from the backend and displays it in multiple PersonRow.vue components using v-for. Although data property types are explicitly defined, I get a warning in the browser console:
[Vue warn]: Invalid prop: Type check failed for prop "person". Expected Person, got Object

Everything is working fine and I could change the property type in PersonRow.vue to Object to get rid of the warning but I would like to have type checks working correctly.

People.vue

<template>
  <div class="container">
    <PersonRow v-for="person in people" :key="person.id" :person="person" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { Person, getPeople } from '../services/person'
import PersonRow from '@/components/PersonRow.vue'

export default defineComponent({
  components: {
    PersonRow
  },
  data () {
    return {
      people: new Array<Person>()
    }
  },
  mounted () {
    getPeople().then(
      response => {
        this.people.push(...response)
      })
  }
})
</script>

PersonRow.vue

<template>
  <div class="row">
    <div class="col">{{ person.givenName }}</div>
    <div class="col">{{ person.familyName }}</div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { Person } from '../services/person'

export default defineComponent({
  props: {
    person: {
      type: Person,
      required: true
    }
  }
})
</script>

person.ts

export class Person {
  constructor (id: number, givenName: string, familyName: string) {
    this.id = id
    this.givenName = givenName
    this.familyName = familyName
  }

  id: number;
  givenName: string;
  familyName: string;
}

export async function getPeople (): Promise<Person[]> {
  const response = await fetch('https://api.example.com/people')
  return await response.json() as Person[]
}
like image 273
Danitechnik Avatar asked Jan 24 '23 16:01

Danitechnik


1 Answers

Annotating Props

export default defineComponent({
  props: {
    person: {
      type: Object as PropType<Person>,
      required: true
    }
  }
})

Deeper dive

Yes, the docs says: In addition, type can also be a custom constructor function and the assertion will be made with an instanceof check

But in order to make it work the object passed into the prop must be created with new Person() constructor. And the problem is your getPeople () function is not creating array of Person instances - it's just type casting array of regular JS objects created with json() to Person[]. Typecasting don't change the runtime type of the object...

like image 146
Michal Levý Avatar answered Jan 29 '23 11:01

Michal Levý