Template ref type inference is incompatible for components with `defineEmits` and VueUse composables
Vue - Official extension or vue-tsc version
2.2.0
VSCode version
N/A
Vue version
3.5.13
TypeScript version
5.7.3
System Info
N/A
package.json dependencies
"dependencies": {
"@vueuse/core": "^12.5.0",
"vue": "^3.5.13"
},
"devDependencies": {
"@types/jsdom": "^21.1.7",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/tsconfig": "^0.7.0",
"typescript": "^5.7.3",
"vite": "^6.0.11",
"vue-tsc": "^2.2.0"
}
Steps to reproduce
- Open provided minmal repro on stackblitz
- Create another terminal window
- Execute
npm run type-checkcommand
What is expected?
type-check script completes without errors.
What is actually happening?
type-check script fails with the following error
src/App.vue:7:37 - error TS2345: Argument of type 'Readonly<ShallowRef<CreateComponentPublicInstanceWithMixins<ToResolvedProps<{}, { eventName: () => any; }>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}> | null>>' is not assignable to parameter of type 'MaybeComputedElementRef<MaybeElement>'.
Type 'Readonly<ShallowRef<CreateComponentPublicInstanceWithMixins<ToResolvedProps<{}, { eventName: () => any; }>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}> | null>>' is not assignable to type 'ShallowRef<MaybeElement, MaybeElement>'.
Type 'Readonly<ShallowRef<CreateComponentPublicInstanceWithMixins<ToResolvedProps<{}, { eventName: () => any; }>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}> | null>>' is not assignable to type 'Ref<MaybeElement, MaybeElement>'.
Types of property 'value' are incompatible.
Type 'CreateComponentPublicInstanceWithMixins<ToResolvedProps<{}, { eventName: () => any; }>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}> | null' is not assignable to type 'MaybeElement'.
Type 'CreateComponentPublicInstanceWithMixins<ToResolvedProps<{}, { eventName: () => any; }>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}>' is not assignable to type 'MaybeElement'.
Type 'CreateComponentPublicInstanceWithMixins<ToResolvedProps<{}, { eventName: () => any; }>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}>' is not assignable to type 'VueInstance'.
Type 'CreateComponentPublicInstanceWithMixins<ToResolvedProps<{}, { eventName: () => any; }>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}>' is not assignable to type '{ $: ComponentInternalInstance; $data: {}; $props: {}; $attrs: Data; $refs: Data; $slots: Readonly<InternalSlots>; $root: ComponentPublicInstance<...> | null; ... 7 more ...; $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (args_0: R, args_1: R, args_2: OnClean...'.
Types of property '$emit' are incompatible.
Type '(event: "eventName") => void' is not assignable to type '(event: string, ...args: any[]) => void'.
Types of parameters 'event' and 'event' are incompatible.
Type 'string' is not assignable to type '"eventName"'.
7 const bounding = useElementBounding(component);
~~~~~~~~~
Found 1 error in src/App.vue:7
Link to minimal reproduction
https://stackblitz.com/edit/vitejs-vite-ypjynt2e?file=src%2FApp.vue,src%2FComponent.vue
Any additional comments?
Current workaround is to import MaybeElementRef type from vueuse and cast the value.
import { type MaybeElementRef } from "@vueuse/core";
useElementBounding(component as MaybeElementRef);
Removal of defineEmits also removes type-check error.
I'm not exactly sure what's causing it and maybe vue-tsc is correct here. Though decided to start an issue here to investigate at the highest level first. If this turns out to be upstream issue at VueUse or even vue - I will reopen there.
It should be a upstream issue.
Okay, thank you @KazariEX. I'll open an issue in VueUse repo then.
Up to you if you wanna keep this one open until it's fixed or close right away.
@romansp, were you able to resolve this issue? I commented on a related issue in VueUse repo but they closed it. This isn't a Vue2 issue.