如何使用 Typescript 在 Composition API 中正确声明静态引用?

How to correctly declare static refs in Composition API using Typescript?

我正在使用组合 API(使用 <script setup lang='ts'>)创建一个引用,用于我的模板:

const searchRef = ref(null)
onMounted(() => { searchRef.value.focus() })

它确实有效,我的代码编译没有错误。然而,IDE(JetBrains Goland 或 Webstorm)抱怨 TS2531: Object is possibly 'null'.

核心解决方案是使用

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Object is possibly 'null'.

但是想了解一下有没有更好的办法

我希望 optional chaining 成为一个解决方案:

const searchRef = ref(null)
onMounted(() => { searchRef.value?.focus() })

代码仍然可以编译,应用程序仍然可以运行,但我现在 TS2339: Property 'focus' does not exist on type 'never'.

解决这个问题的正确方法是什么?

解决此问题的一种可能方法是手动添加正确的类型:

const searchRef: Ref<HTMLElement | null> = ref(null);
onMounted(() => { searchRef.value?.focus() });

注意:如果 ref 以 Vue 组件为目标(例如 Ref<HTMLElement | Vue | null>),HTMLElement 可能会有所不同。

对于模板引用,在初始化时将通用类型参数传递给 ref。通用类型应与模板引用的目标元素的类型相匹配。

以下是本机 HTML 元素上模板引用的一些示例:

const htmlElemRef = ref<HTMLElement>()         // => type: HTMLElement | undefined
const inputRef = ref<HTMLInputElement>()       // => type: HTMLInputElement | undefined
const textareaRef = ref<HTMLTextAreaElement>() // => type: HTMLTextAreaElement | undefined

null 初始化是可选的,我经常省略它以获得更简洁的代码。结果类型是 <T | undefined>,它比 null 更正确,因为如果模板中不存在元素,ref 实际上是 undefinedref 的值仍然需要可选链接(假设它可能是 undefined)。

示例:

const searchRef = ref<HTMLInputElement>()
onMounted(() => { searchRef.value?.focus() })

正如@Kurt 所指出的,Vue 组件上的模板引用需要不同的类型。 ref 的通用类型是 InstanceType of the component's type (from a .vue import) (docs):

InstanceType<typeof MyComponentDefinition>

示例:

import HelloWorld from '@/components/HelloWorld.vue'

const helloRef = ref<InstanceType<typeof HelloWorld>>()

注意:要在 TypeScript 文件中使用 Volar 而不是 Vue SFC,请确保启用 Volar's Takeover Mode.

demo