[英]Vue3: How to type a component instance template ref with exposed methods?
I have this component A with an exposed method send
我有这个组件 A 有一个暴露的方法
send
A.vue: 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
B.vue 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?我如何键入导入的组件,以便当我通过 refs 调用它的方法时,它会检查公开的方法名称和传递的类型 arguments?
I tried what I could google: ComponentPublicInstance<typeof ComponentA>
but it doesn't seem to check the methods.我尝试了我可以用谷歌搜索的内容:
ComponentPublicInstance<typeof ComponentA>
但它似乎没有检查方法。
EDIT:编辑:
here's shims-vue.d.ts (as generated by vue-cli):这是 shims-vue.d.ts(由 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.如您所见,在 HelloWorld.vue 中,
a
是对 ComponentA 实例的引用。 I attempted to type it with const a = ref<InstanceType <typeof ComponentA>>()
, but no luck, it gets typed as any
我试图用
const a = ref<InstanceType <typeof ComponentA>>()
来输入它,但没有运气,它被输入为any
The instance type of ref()
is a Ref<T>
, where T
(defaults to any
) specifies the type of its .value
property. ref()
的实例类型是Ref<T>
,其中T
(默认为any
)指定其.value
属性的类型。
You didn't provide the generic type, and no initializer argument exists to infer the type from, so TypeScript assumes T
is any
, and thus a.value
has a type of any
.您没有提供通用类型,并且不存在可从中推断类型的初始化参数,因此 TypeScript 假定
T
是any
,因此a.value
的类型是any
。 Therefore, a.value.send
is also of type any
, which would not provide any type safety (as you had observed).因此,
a.value.send
也是类型any
,它不会提供任何类型安全性(如您所见)。
In this case, you should declare the generic type of ref
with:在这种情况下,您应该声明
ref
的通用类型:
👇
const a = ref<InstanceType<typeof ComponentA>>()
a.value?.send(22) // error: Argument of type 'number' is not assignable to parameter of type 'string'.
As far as TypeScript is concerned, ComponentA is of type DefineComponent<{}, {}, any>
, because your shims-vue.d.ts
declares it as such.就 TypeScript 而言,ComponentA 的类型为
DefineComponent<{}, {}, any>
,因为您的shims-vue.d.ts
将其声明为此类。 (I imagine you'll have more luck with import ComponentA
as opposed to import { ComponentA }
, too.) TypeScript does not understand how to parse Vue SFC files, so TypeScript is forced to trust your .d.ts
file. (我想
import ComponentA
相对于import { ComponentA }
也会更幸运。)TypeScript 不了解如何解析 Vue SFC 文件,因此 TypeScript 被迫信任您的.d.ts
文件。
In IDEs like VSCode using extensions like Volar or Vetur , you might get more specific type checking than TypeScript alone will get you;在像 VSCode 这样使用 Volar 或 Vetur 扩展的 IDE 中,你可能会得到比 TypeScript 更具体的类型检查; that's because Vetur and Volar are smart enough to read Vue SFC files and type them appropriately, disregarding the global
.d.ts
shim.那是因为 Vetur 和 Volar 足够聪明,可以读取 Vue SFC 文件并适当地键入它们,而忽略全局
.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.如果你想要更智能的 TypeScript 检查而不使用 IDE,那么就像Vue Typescript 概述部分一样,你需要使用
vue-tsc
,这是一个 TypeScript 包装器,它与 Volar 共享代码但理解 SFC 文件。 You might can also use vue-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.您也可以使用
vue-tsc
生成更具体的.d.ts
文件,该文件会写出上下文 TypeScript 需要在不使用 Vue-aware 包装器的情况下验证您的 SFC。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.