Vue3:如何使用公开的方法输入组件实例模板引用?

vch*_*vch 7 typescript vue.js vuejs3 vue-script-setup

我有这个组件 A 和一个公开的方法send

A.vue:

<script setup lang="ts">
function send(data: string) {
  console.log(data)
}

defineExpose({ send })
</script>
Run Code Online (Sandbox Code Playgroud)

以及导入该组件的组件B

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>
Run Code Online (Sandbox Code Playgroud)

如何键入导入的组件,以便当我通过 refs 调用其方法时,它会检查公开的方法名称和传递参数的类型?

我尝试了谷歌搜索:ComponentPublicInstance<typeof ComponentA>但它似乎没有检查方法。

编辑:

这是 shims-vue.d.ts (由 vue-cli 生成):

declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

Run Code Online (Sandbox Code Playgroud)

编辑:

这是复制品。

如您所见,在 HelloWorld.vue 中,a引用的是 ComponentA 的实例。我尝试用 键入它const a = ref<InstanceType <typeof ComponentA>>(),但没有运气,它被键入为any

VSCode 的截图

ton*_*y19 14

的实例类型ref()是 a Ref<T>,其中T(默认为any)指定其属性的类型.value。

您没有提供泛型类型,并且不存在用于推断类型的初始值设定项参数,因此 TypeScript 假定T为any,因此a.value类型为any。因此,a.value.send也是类型any,它不会提供任何类型安全(正如您所观察到的)。

在这种情况下,您应该声明 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'.
Run Code Online (Sandbox Code Playgroud)

TypeScript 实际错误的屏幕截图

  • 我尝试了“InstanceType”,但对我来说它会导致“any”类型。从你的屏幕截图我可以告诉你,情况并非如此。您是否在某处明确定义了 ComonentA 的类型? (2认同)

Jef*_*ica 2

就 TypeScript 而言, ComponentA 的类型是DefineComponent<{}, {}, any>,因为您shims-vue.d.ts如此声明它。(我想你也会比 更幸运import ComponentA。import { ComponentA })TypeScript 不理解如何解析 Vue SFC 文件,因此 TypeScript 被迫信任你的.d.ts文件。

在VSCode 等使用 Volar 或 Vetur 等扩展的 IDE中,您可能会得到比单独使用 TypeScript 更具体的类型检查;这是因为 Vetur 和 Volar 足够聪明,可以读取 Vue SFC 文件并适当地键入它们,而忽略全局.d.tsshim。

如果您想要在不使用 IDE 的情况下进行更智能的 TypeScript 检查,那么就像Vue Typescript 概述部分一样,您需要使用vue-tsc,它是一个与 Volar 共享代码但理解 SFC 文件的 TypeScript 包装器。您还可以用来vue-tsc生成一个更具体的.d.ts文件,该文件将写出 TypeScript 验证 SFC 所需的上下文,而无需使用 Vue 感知包装器。