Skip to content
New issue

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

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

Already on GitHub? # to your account

Calling prop fields in the template (like props.foo) doesn't work with withDefaults #3204

Closed
rodrigocfd opened this issue May 19, 2023 · 17 comments · Fixed by #3636
Closed
Labels
bug Something isn't working

Comments

@rodrigocfd
Copy link

This is issue originated from this vue/core discussion. Apparently it's not a vue/core error.

This is the error:

gen-err

Reproducible:

<script setup lang="ts" generic="T">
const props = withDefaults(defineProps<{
	value?: T | null;
	list: T[];
}>(), {
	value: null,
});
</script>

<template>
	<select>
		<option v-for="item of props.list">

		</option>
	</select>
</template>
@xiaoxiangmoe
Copy link
Collaborator

Temp solution: change props.list to list.

@xiaoxiangmoe
Copy link
Collaborator

Hi, @pikax

This also seems to be a vue/core type issue

import { defineComponent, defineProps, withDefaults } from "vue";
export default <T>() => {
  const props = withDefaults(
    defineProps<{
      value?: T | null;
      list: T[];
    }>(),
    {
      value: null,
    }
  );
  const __VLS_internalComponent = defineComponent({
    setup() {
      return {
        props: props,
      };
    },
  });
  const instance: InstanceType<typeof __VLS_internalComponent> = null as any;

  // Property 'list' does not exist on type 'PropsWithDefaults<{ value?: T | null | undefined; list: T[]; }, { value: null; }, [T | null | undefined] extends [boolean | undefined] ? "value" : never> extends Ref<...> ? V : PropsWithDefaults<...> extends Ref<...> | undefined ? unknown extends V ? undefined : V | undefined : PropsWithDefaults<...>'.ts(2339)
  // @ts-expect-error
  instance.props.list;
};

@xiaoxiangmoe xiaoxiangmoe added need transfer bug Something isn't working and removed need transfer upstream labels May 19, 2023
@pikax
Copy link
Member

pikax commented May 19, 2023

@xiaoxiangmoe you're still changing the type of props by returning them on the setup, the clean $props are located _ctx.$props and I would recommend using them instead.

image
<script setup lang="ts" generic="T">
const props = withDefaults(defineProps<{
	value?: T | null;
	list: T[];
}>(), {
	value: null,
});
</script>

<template>
	<select>
		<option v-for="item of list">

		</option>
      {{ $props.list }}
    </select>
</template>

While testing this I've noticed Volar does not resolve the type correctly when using instance type, altho it works in the <template>?

eg:

import  MyComp from './MyComp.vue'

// this is errored
const el = ref<null | InstanceType<typeof MyComp>>(null)
image

fixed code is

const el = ref<null | InstanceType<typeof MyComp<any>>>(null)

@Danny2462
Copy link

fixed code is

const el = ref<null | InstanceType<typeof MyComp<any>>>(null)

This fix doesn't work for me, still results in #3206

Vue.volar@v1.7.8
Vue.vscode-typescript-vue-plugin@v1.7.8
takeover mode

@emilyAzz
Copy link

Hello, I have vue version 3.3.4 and upon using the generic type within the defineProps with defaults value managad with the new updates to make it work but when I come to build I encounter the below error with the defineEmits when I am emitting a generic type back

error TS5088: The inferred type of 'default' references a type with a cyclic structure which cannot be trivially serialized. A type annotation is necessary.

Tried <script setup lang="ts" generic="I extends any"> and also adding
"vueCompilerOptions": { "jsxTemplates": true, "experimentalRfc436": true }

but nothing is removing this error, anyone has any idea how this can be solved?

@rodrigocfd
Copy link
Author

@xiaoxiangmoe @pikax Is there any progress on this?

@so1ve
Copy link
Member

so1ve commented Jun 26, 2023

@rodrigocfd I'm working on this now, but I'm not sure if I can fix it 😂

@ouou12138
Copy link

When I use generic components, I get this error, How can I resolve it?

<template>
  <div>{{anyData.name}}</div> // Property 'name' 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; }'.ts(2339)。

  <button @click="emit('taptap',anyData)"></button> // Argument of 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 parameter of type 'T'.
</template>
<script lang='ts' setup generic='T extends { name: string }'>
defineProps<{
  anyData:T,
}>()
const emit = defineEmit<{
  (event:'taptap',value:T):void
}>()
</script>

however, when i use this component in other component, i can get actually types

@lmiller1990
Copy link
Member

lmiller1990 commented Aug 4, 2023

I have the same issue. If you make the T into T[], it works fine, though. I am not clear why this would the case. Eg:

<template>
  <div>{{anyData[0].name}}</div> 
</template>

<script lang="ts" setup generic="T extends { name: string }">
defineProps<{
  anyData:T[],
}>()
</script>

This is dup of #3405.

Is this a Volar issue or a Vue issue? Based on the OP, it's Volar. I'll have a poke around.

Weird - I guess this worked at one point, at least according to the announcement post. I wonder if there has been a regression?

@so1ve
Copy link
Member

so1ve commented Aug 4, 2023

Typescript issue I guess? :( IMO there are some type errors in vue core.

@lmiller1990
Copy link
Member

I am trying to reproduce without using an SFC to establish where the issue is.

I would be surprised if this was in Vue core - the PR is here, and it looks like it should be just fine: https://github.com/vuejs/core/pull/7963/files

@lmiller1990
Copy link
Member

This works fine, I do not think it is in Vue core.

import { defineComponent, h, ref } from "vue";

export interface ListItem {
  id: string;
  title: string;
}

const Comp = defineComponent(
  // TODO: babel plugin to auto infer runtime props options from type
  // similar to defineProps<{...}>()
  <T extends ListItem>(props: { msg: T; list: T[] }) => {
    // use Composition API here like in <script setup>
    const count = ref(0);

    return () => h("div", props.msg.title);
  }
);
image

@rodrigocfd
Copy link
Author

@johnsoncodehk While this works as expected in Volar and dev environment, it still crashes at npm run build. Could you please route this issue to the appropriate Vue repo?

@so1ve
Copy link
Member

so1ve commented Oct 9, 2023

Hi @rodrigocfd, could you please explain which kind of "crash"? Does it mean Vue Compiler cannot compile such code, or vue-tsc cannot generate types for it?

@rodrigocfd
Copy link
Author

@so1ve Compilation error. It says "props.foo doesn't exist":

error TS2339: Property 'modelValue' does not exist on type 'PropsWithDefaults<{ modelValue: T; lista: { val: T; texto: string; }[]; titulo?: string | undefined; }, { titulo: "Selecione..."; }, [T] extends [boolean | undefined] ? "modelValue" : never> extends Ref<...> ? V : PropsWithDefaults<...> extends Ref<...> | undefined ? unknown extends V ? undefined : V | undefined : P...'.

@so1ve
Copy link
Member

so1ve commented Oct 9, 2023

Which version of vue-tsc are you using?

@rodrigocfd
Copy link
Author

I was using v1.8.15, after updating to v1.8.18 (latest) it's working fine. Sorry, my bad.

Thanks for the help.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants