简体   繁体   English

Vue3:如何使用暴露的方法键入组件实例模板引用?

[英]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

来自 vscode 的屏幕截图

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 假定Tany ,因此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'.

TypeScript 错误的截图

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM