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

Cannot use InstanceType<typeof Comp<any>>> on generic components #3206

Closed
pikax opened this issue May 19, 2023 · 24 comments · Fixed by #3536
Closed

Cannot use InstanceType<typeof Comp<any>>> on generic components #3206

pikax opened this issue May 19, 2023 · 24 comments · Fixed by #3536
Labels
bug Something isn't working

Comments

@pikax
Copy link
Member

pikax commented May 19, 2023

Since the push of adding generic components on Vue 3.3.0, we don't seem able to get the InstanceType aka public instance anymore.

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

<template>
    <select>
       // code
    </select>
</template>
<script lang="ts">
import MyComp from './MyComp.vue'

// This has error
const el = ref<null | InstanceType<typeof MyComp<any>>>( null )

</script>
<template>
   <my-comp ref="el" list="[]"/>
</template>
@zf1998
Copy link

zf1998 commented May 25, 2023

I aslo!!! use [email protected][email protected].

@johnsoncodehk
Copy link
Member

johnsoncodehk commented May 25, 2023

When using generic, Volar defines the component as a functional component, so you should use ReturnType instead of InstanceType:

Another option is to use ComponentExposed from vue-component-type-helpers:

import MyComp from './MyComp.vue'
import type { ComponentExposed } from 'vue-component-type-helpers'

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

@varlamov88
Copy link

Vue 3.3.4
Volar 1.7.8
Without generic and with InstanceType
Screenshot_2

With generic and ReturnType/ComponentExposed
Screenshot_1

@oddcelot
Copy link

@varlamov88 Depends on how badly you need it, but I deconstructed the type into a new one based on DefineComponent just to get it to work at the moment over here vuejs/core#8373 (comment)

@johnsoncodehk johnsoncodehk reopened this Jun 23, 2023
@johnsoncodehk johnsoncodehk added bug Something isn't working and removed question Further information is requested labels Jun 23, 2023
@johnsoncodehk
Copy link
Member

I can confirm that ComponentExposed is not working, and ReturnType not working is correct behavior.

@satrong
Copy link

satrong commented Jul 7, 2023

This is my temporary solution, but it's not perfect😂. I'm looking forward to the official release of the final solution.

import { type DefineComponent } from 'vue'
import MyComp from './MyComp.vue'

type ComponentInstance<T> = T extends new (...args: any[]) => infer R
  ? R
  : T extends (...args: any[]) => infer R
    ? R extends { __ctx?: infer K }
      ? Exclude<K, void> extends { expose: (...args: infer K) => void }
        ? K[0] & InstanceType<DefineComponent>
        : any
      : any
    : any

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

@Bernard-Borg
Copy link

bump - need this please

@so1ve
Copy link
Member

so1ve commented Jul 15, 2023

@Bernard-Borg #3271, please be patient :)

@f3oall
Copy link

f3oall commented Sep 5, 2023

Hey guys, it's really blocking the use of generic components, any chance that it will be fixed soon?

Thanks for the great tools btw :)

@so1ve
Copy link
Member

so1ve commented Sep 6, 2023

Hey folks 👋 Could you please checkout #3536? Does it work for you?

Note

You should use ComponentExposed from the vue-component-type-helpers packages instead of TypeScript's built-in ReturnType or InstanceType utilities.

@joris-gallot
Copy link

Hey! how I'm supposed to do, when I want for example $el from a generic component?

@cernymatej
Copy link

For some reason, I am getting {} type from the ComponentExposed utility. Have any of you encountered something similar?

@szulcus
Copy link

szulcus commented Feb 5, 2024

I have the same problem. Why this issue is closed?

@so1ve
Copy link
Member

so1ve commented Feb 6, 2024

#3206 (comment)

@arthaali
Copy link

ComponentExposed

Hello, I am still facing this issue and the fix is not really clear.
the link you provided does not exist and I can't find how to use ComponentExposed
can you please report the fix?
Can you maybe support here? @so1ve
Thank you

@so1ve
Copy link
Member

so1ve commented Feb 16, 2024

Install vue-component-type-helpers, import { ComponentExposed } from 'vue-component-type-helpers', then replace InstanceType with ComponenttExposed.

@postpostscript
Copy link

postpostscript commented Feb 16, 2024

Edit: I removed my original comment since I see that the PR so1ve linked fixes the issue, and I got it to work! I think what happened is that after manually updating the package I didn't properly reload the Volar project. For anyone else who is still getting this issue, I would check that node_modules/vue-component-type-helpers is in fact on 1.8.27, since mine wasn't after I updated Vue to 3.4 (maybe because of my package-lock? not sure). Thanks for the fix!

@szulcus
Copy link

szulcus commented Feb 27, 2024

@so1ve I have wrong Vuelidate (https://vuelidate-next.netlify.app/#getting-started-1) type. It should be available without .value 🤔
image
image
Computed variable changedData works fine (without .value suffix). For now I have vuelidate: computed(() => vuelidate.value) as workaround in defineExpose().

@LeoKun1231
Copy link

Looking forward to your update

@mauroviniciussilva
Copy link

This is my temporary solution, but it's not perfect😂. I'm looking forward to the official release of the final solution.

import { type DefineComponent } from 'vue'
import MyComp from './MyComp.vue'

type ComponentInstance<T> = T extends new (...args: any[]) => infer R
  ? R
  : T extends (...args: any[]) => infer R
    ? R extends { __ctx?: infer K }
      ? Exclude<K, void> extends { expose: (...args: infer K) => void }
        ? K[0] & InstanceType<DefineComponent>
        : any
      : any
    : any

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

I've just tried this solution and for some reason Typescript were complaning about K being duplicated, so I had to use this way:

import { type DefineComponent } from 'vue'

export type GenericComponentInstance<T> = T extends new (...args: any[]) => infer R
  ? R
  : T extends (...args: any[]) => infer R
    ? R extends { __ctx?: infer K }
      ? Exclude<K, void> extends { expose: (...args: infer Y) => void }
        ? Y[0] & InstanceType<DefineComponent>
        : any
      : any
    : any;

@so1ve
Copy link
Member

so1ve commented Jul 31, 2024

ComponentExposed is not suitable for you usecase. It is used to get things exposed by defineExposed.

@TheDutchCoder
Copy link

ComponentExposed is not suitable for you usecase. It is used to get things exposed by defineExposed.

Am I not running into the same issue though? IntstanceType not working with components that have a generic?
It'd also what you recommended here: #3206 (comment)

@ethanchristensen01
Copy link

Another option is to use ComponentExposed from vue-component-type-helpers

For anybody checking this issue in the future, it's worth noting that this URL is incorrect. The correct URL is https://github.com/vuejs/language-tools/tree/master/packages/component-type-helpers

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