I have this component A with an exposed method send
A.vue:
<script setup lang="ts">
function send(data: string) {
console.log(data)
}
defineExpose({ send })
</script>
And the component B which imports this component
B.vue
<template>
<ComponentA ref="a" />
</template>
<script setup lang="ts">
import ComponentA from '@/component-a.vue'
const a = ref()
onMounted(() => a.value.send(22)) // should be a type error
</script>
How do I type the imported component, so that when I call its methods through refs, it checks exposed method names and types of passed arguments?
I tried what I could google: ComponentPublicInstance<typeof ComponentA>
but it doesn't seem to check the methods.
EDIT:
here's shims-vue.d.ts (as generated by vue-cli):
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
EDIT:
Here's the reproduction.
As you can see, in HelloWorld.vue, a
is ref to an instance of ComponentA. I attempted to type it with const a = ref<InstanceType <typeof ComponentA>>()
, but no luck, it gets typed as any
As far as TypeScript is concerned, ComponentA is of type
DefineComponent<{}, {}, any>
, because yourshims-vue.d.ts
declares it as such. (I imagine you'll have more luck withimport ComponentA
as opposed toimport { ComponentA }
, too.) TypeScript does not understand how to parse Vue SFC files, so TypeScript is forced to trust your.d.ts
file.In IDEs like VSCode using extensions like Volar or Vetur, you might get more specific type checking than TypeScript alone will get you; that's because Vetur and Volar are smart enough to read Vue SFC files and type them appropriately, disregarding the global
.d.ts
shim.If you want smarter TypeScript checking without using an IDE, then as on the Vue Typescript Overview section you'll need to use
vue-tsc
, which is a TypeScript wrapper that shares code with Volar but understands SFC files. You might can also usevue-tsc
to generate a more-specific.d.ts
file, which would write out the context TypeScript needs to validate your SFCs without using the Vue-aware wrapper.