"VueJS 3组合式API和TypeScript类型问题:将props传递到setup时,属性'user'在类型上不存在。"

12

我很难弄清楚我做错了什么,使得TypeScript无法理解props.userUserInterface类型。任何建议或指针都会很棒。

vue@3.1.1,typescript@4.2.2,quasar@2.0.0-rc.3. 这感觉更像是原生VueJS或TypeScript问题,而不是与Quasar有关的任何事情。

参考UserInterface:

export default interface UserInterface {
  id: number,
  email: string,
  name: string,
  agent_id: string
}

组件:

<template>
  <q-avatar :color="color" :text-color="textColor" :size="size" :title="user.name" style="outline: 2px solid #ffffff">
    {{ initials(user.name) }}
  </q-avatar>
</template>

<script lang="ts">
import UserInterface from 'logic/interfaces/UserInterface'
import {computed, defineComponent, PropType} from 'vue'

const colors: Record<string, string> = {
  A: 'blue',
  K: 'black',
  R: 'purple',
  S: 'primary'
}

export default defineComponent({
  name: 'UserIcon',
  props: {
    user: {
      type: Object as PropType<UserInterface>,
      required: true
    },
    size: {
      type: String,
      required: false,
      default: 'lg',
      validator: function (value: string) {
        return ['xs', 'sm', 'md', 'lg', 'xl'].indexOf(value) !== -1
      }
    },
    textColor: {
      type: String,
      required: false,
      default: 'white'
    }
  },
  setup (props) {
    const initial = props.user.agent_id.charAt(0)
    const color = computed(() => {
      return colors[initial] || 'green'
    })

    return {
      color,
      initials (name: string) {
        const names = name.split(' ')
        let initials = names[0].charAt(0)
        if (names.length > 1) {
          initials += names[names.length - 1].charAt(0)
        }

        return initials
      }
    }
  }
})
</script>

VueJS 3文档https://v3.vuejs.org/guide/typescript-support.html#using-with-composition-api指出:

在setup()函数中,您无需为props参数传递类型,因为它将从组件选项中的props中推断出类型。

然而,我仍然遇到了编译错误,并不确定自己缺少了什么。

结果:

Failed to compile.

TS2339: Property 'user' does not exist on type 'Readonly<LooseRequired<Readonly<{ [x: number]: string; } & { length?: number | undefined; toString?: string | undefined; toLocaleString?: string | undefined; concat?: string[] | undefined; join?: string | undefined; ... 15 more ...; includes?: ((searchElement: string, fromIndex?: number | undefined) => boolean) | un...'.
    38 |   },
    39 |   setup (props) {
  > 40 |     const initial = props.user.agent_id.charAt(0)
       |                           ^^^^
    41 |     const color = computed(() => {
    42 |       return colors[initial] || 'green'
    43 |     })

注意: 在有问题的代码行上方添加 @ts-ignore 确实可以去除错误,但这并没有解决问题。

我尝试删除 node_modules 并重新启动所有内容以确保它不是故障。

它正在运行在 Docker 镜像中。

1个回答

12
prop声明中,Vue文档要求对于validatordefault,要么使用箭头函数,要么提供显式的this参数:

WARNING

Because of a design limitation in TypeScript when it comes to type inference of function expressions, you have to be careful with validator and default values for objects and arrays:

import { defineComponent, PropType } from 'vue'

interface Book {
  title: string
  year?: number
}

const Component = defineComponent({
  props: {
    bookA: {
      type: Object as PropType<Book>,
      // Make sure to use arrow functions
      default: () => ({
        title: 'Arrow Function Expression'
      }),
      validator: (book: Book) => !!book.title
    },
    bookB: {
      type: Object as PropType<Book>,
      // Or provide an explicit this parameter
      default(this: void) {
        return {
          title: 'Function Expression'
        }
      },
      validator(this: void, book: Book) {
        return !!book.title
      }
    }
  }
})
Anders Hejlsberg, TypeScript的首席架构师,在GitHub评论中解释了这个问题:
这是一个设计限制。类似于#38872。没有参数的箭头函数不具有上下文敏感性,但是没有参数的函数表达式具有上下文敏感性,因为存在隐含的this参数。任何上下文敏感的内容都将被排除在类型推断的第一阶段之外,而这个阶段决定了我们将为上下文类型化的参数使用哪些类型。因此,在原始示例中,当a属性的值是箭头函数时,我们成功地对A进行了推断,在为ba参数分配上下文类型之前。但是当该值为函数表达式时,我们没有进行推断,因此a参数的类型为unknown

Translated answer:

你的某个属性与PropOptions的预期签名不匹配,这显然会破坏setup()props参数的类型推断。具体来说,由于某种原因,TypeScript无法看到size.validator的签名与PropOptions.validator的类型相匹配。

有趣的是,如果将validator更改为箭头函数,则props的类型推断将成功:

export default defineComponent({
  props: {
    size: {
      type: String,
      required: false,
      default: 'lg',
      //validator: function (value: string) { /*...*/ },
      validator: (value: string) => { /*...*/ },
    },
  }
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接