将道具传递给设置时的VueJS 3组合API和TypeScript类型问题:类型上不存在属性“用户”

Posted

技术标签:

【中文标题】将道具传递给设置时的VueJS 3组合API和TypeScript类型问题:类型上不存在属性“用户”【英文标题】:VueJS 3 Composition API and TypeScript type issue when passing props into setup: Property 'user' does not exist on type 【发布时间】:2021-09-05 12:03:19 【问题描述】:

我正在努力找出我做错了什么让 TypeScript 理解 props.userUserInterface 类型,任何建议或指针都会很棒

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

用户界面供参考:

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】:

对于prop 声明中的validatordefault,Vue docs 规定(1)使用箭头函数,或(2)提供显式this 参数:

警告

由于 TypeScript 中的 design limitation 在涉及函数表达式的类型推断时,您必须小心对象和数组的 validatordefault 值:

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
      
    
  
)

TypeScript 的首席架构师 Anders Hejlsberg 在GitHub comment 中解释了这个问题:

这是一个设计限制。类似于#38872。没有参数的 [n] 箭头函数不是上下文敏感的,但是没有参数的函数表达式是上下文敏感的,因为隐含的 this 参数。任何与上下文相关的内容都被排除在类型推断的第一阶段之外,该阶段确定我们将用于上下文类型参数的类型。因此,在原始示例中,当a 属性的值是箭头函数时,我们在将上下文类型分配给b 的a 参数之前成功地推断出A。但是当值是一个函数表达式时,我们不做任何推断,a 参数被赋予类型unknown


原答案:

您的一个道具与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) =>  /*...*/ ,
    ,
  
)

【讨论】:

以上是关于将道具传递给设置时的VueJS 3组合API和TypeScript类型问题:类型上不存在属性“用户”的主要内容,如果未能解决你的问题,请参考以下文章

VueJs:将动态组件作为道具传递给另一个组件并渲染它们

将道具动态传递给VueJS中的动态组件

如何在 vuejs 中通过 <router-link /> 将道具传递给命名视图?

在VueJS 2中通过v-for中的道具将数据从父级传递给子级

当路由器在 vuejs2.0 中更改时,vue-route 将不同的道具传递给不同的视图组件?

如何在Vuejs中将反应性道具传递给孩子