Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Property does not exist on type '[{ type: PropType<T>; required: true; }] #3267

Closed
Ragura opened this issue Jun 9, 2023 · 6 comments
Closed
Labels
duplicate This issue or pull request already exists upstream

Comments

@Ragura
Copy link

Ragura commented Jun 9, 2023

This is a continuation of another issue where I bundled a few issues together which I probably shouldn't have done because it makes it hard to track.

I once again would like to offer my reproduction of this issue: https://github.com/Ragura/vue-issue-repro

The reproduction includes 3 components, of which 2 are important to this issue: DropdownDestructuring and DropdownTraditional.

Both components show the error: Property 'id' does not exist on type '[{ type: PropType<T>; required: true; }] extends [Prop<infer V, infer D>] ? unknown extends V ? IfAny<V, V, D> : V : { type: PropType<T>; required: true; }'.

Code that shows the error looks like this:

<script setup lang="ts" generic="T extends { id: number }">
const props = withDefaults(defineProps<{
  options?: T[]
  title?: string
  modelValue: T
}>(), {
  title: '',
  options: () => [],
})

const emit = defineEmits(['update:modelValue'])

function updateSelected(event: Event) {
  const target = event.target as HTMLSelectElement
  const id = target.value
  const option = props.options.find(option => option.id === +id)
  emit('update:modelValue', option)
}
</script>

<template>
  <h2>{{ title }}</h2>
  <select @change="updateSelected">
    <option 
      v-for="option in options"
      :key="option.id" 
      :value="option.id" 
      :selected="modelValue.id === option.id"> <-- ERROR HERE!
      {{ option }}
    </option>
  </select>
</template>

For the options prop, the id of each array item is being recognized, even though it also originates from T.

I am using the following:
vue-tsc: 1.7.11
vue: 3.3.4
Vue Language Features extension version 1.7.11, running takeover mode pointed to local vue-tsc typescript version 5.0.4.
Using VSCode insiders.

@so1ve
Copy link
Member

so1ve commented Jun 19, 2023

This is a vue core type issue :(

@so1ve so1ve added the upstream label Jun 26, 2023
@Soviut
Copy link

Soviut commented Jun 28, 2023

I had a similar issue that I posted here on StackOverflow

https://stackoverflow.com/questions/76571246/why-is-my-generic-v-for-key-giving-a-type-error-in-vue-3-3

My temporary solution was

<li
  v-for="(item, i) in items"
  :key="
    //@ts-ignore
    item[itemKey]
  "
>

UPDATE: For posterity, several solutions were offered in the answer I got on Stack Overflow.

The simplest seems to be just converting the key to a string which is one of the three allowed types (string | number | Symbol).

<li
  v-for="(item, i) in items"
  :key="String(item[itemKey])"
>

However, there are more in-depth solutions that involve type narrowing as well.

@WhiteAbeLincoln
Copy link

I'm also having this issue.
Minimal reproduction:

<template>
<label :class="[{ active: value?.key === target.key}]">foo</label>
                                           <!-- ~~~ Property 'key' does not exist on type '[{ type: PropType<Target>; required: true; }] extends [Prop<infer V, infer D>] ? unknown extends V ? IfAny<V, V, D> : V : { type: PropType<Target>; required: true; }'.ts(2339) -->
</template>
<script setup lang="ts" generic="Target extends { key: string }">
defineProps<{ target: Target; value?: Target }>()
</script>

The type checking works correctly within the script block. I can work around this issue by adding a computed ref which returns the key property for the value & target props.

<template>
<label :class="[{ active: valKey === targetKey}]">foo</label>
</template>
<script setup lang="ts" generic="Target extends { key: string }">
import { computed } from 'vue';

const props = defineProps<{ target: Target; value?: Target }>()
const valKey = computed(() => props.value?.key)
const targetKey = computed(() => props.target.key)
</script>

@StrikeAgainst
Copy link

I've got this issue as well, it seems only to apply though when you use the prop directly via macro.

Minimal reproduction with workaround:

<script setup lang="ts" generic="T extends number">
import NumberInput from './NumberInput.vue' // props: { value: number }

const props = defineProps<{
  genericNumber: T
}>()
</script>

<template>
  <NumberInput :value="genericNumber" /> <!-- Type '[{ type: PropType<T>; required: true; }] extends [Prop<infer V, infer D>] ? unknown extends V ? IfAny<V, V, D> : V : { type: PropType<T>; required: true; }' is not assignable to type 'number'.ts(2322) -->
  <NumberInput :value="props.genericNumber" /> <!-- works fine -->
</template>

@so1ve
Copy link
Member

so1ve commented Jan 13, 2024

Duplicate of #3820

@so1ve so1ve marked this as a duplicate of #3820 Jan 13, 2024
@so1ve so1ve closed this as not planned Won't fix, can't repro, duplicate, stale Jan 13, 2024
@so1ve so1ve added the duplicate This issue or pull request already exists label Jan 13, 2024
@so1ve
Copy link
Member

so1ve commented Jan 13, 2024

Please track in #3820.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists upstream
Projects
None yet
Development

No branches or pull requests

5 participants