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

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.

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

Successfully merging a pull request may close this issue.

8 participants