Skip to content

组合式 API 的类型声明

组合式的类型声明主要集中在:

  • 相关的 API
  • 对 HTML 和组件的 ref 引用;
  • 事件;

ref

有3种方式对 ref 进行类型声明

  1. 泛型



 
 
 


<script setup lang="ts">
import { ref } from 'vue'

const year = ref<string | number>('200')
const phone = ref<number>(123)
const visible = ref<boolean>(false)
</script>
1
2
3
4
5
6
7
  1. interfacetype

对于复杂的数据类型,比如对象或者数组,可以使用 interface 或 type 进行类型声明。

Vue3 还提供了通过 Ref 的内置类型来对 ref() 进行类型声明的方式,但这种方式稍显繁琐,不推荐使用,但也可以来认识一下。



 

 




<script setup lang="ts">
import { ref } from 'vue'
import type { Ref } from 'vue'

const year: Ref<string | number> = ref('2020')

year.value = 2020
</script>
1
2
3
4
5
6
7
8

reactive

reactive 类型声明有两种方式。

  1. 直接使用 interface 或者 type
  1. 通过泛型参数的形式增加类型
<script setup lang="ts">
import { reactive } from 'vue'

interface Book {
  title: string
  year?: number
}

const book = reactive<Book>({ title: 'Vue3' })
</script>
1
2
3
4
5
6
7
8
9
10

提示

Vue 官方不推荐使用 reactive() 的泛型参数,因为处理了深层次 ref 解包的返回值与泛型参数的类型不同。

computed

computed 类型声明有两种方式。

  1. 自动推导

computed() 会从其计算函数的返回值上推导出类型。






 
 
 
 


<script setup lang="ts">
import { ref, computed } from 'vue'

const count = ref(0)

// double 推导得到的类型:ComputedRef<number>
const double = computed(() => count.value * 2)
// website 推导得到的类型:ComputedRef<string>
const website = computed(() => count.value + 'devcursor')
</script>
1
2
3
4
5
6
7
8
9
10
  1. 通过泛型参数显式指定类型





 
 
 
 
 
 
 
 


<script setup lang="ts">
import { ref, computed } from 'vue'

const count = ref(0)

const double = computed<number>(() => {
  // 若返回值不是 number 类型则会报错
  return count.value * 2
})
const user = computed<string>(() => {
  // 若返回值不是 string 类型则会报错
  return 'devcursor' + count.value
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

provide

Vue 提供了一个 InjectionKey 接口,它是一个继承自 Symbol 的泛型类型,可以用来在提供者和消费者之间同步注入值的类型

以上的方式都需要额外定义 key 来使用,也可以直接字符串的形式来定义 key。

<script setup lang="ts">
import { provide } from 'vue'

provide('foo', 'bar')
</script>
1
2
3
4
5

inject

对于 inject 的类型声明,如果 provide 的 key 的类型是声明式提供的话(provide 类型声明的第一种形式)。







 


<script setup lang="ts">
import { inject } from 'vue'
import type { InjectionKey } from 'vue'

const name = Symbol() as InjectionKey<string>

const foo = inject(name) // foo 的类型:string | undefined
</script>
1
2
3
4
5
6
7
8

如果 provide 的 key 直接使用的字符串形式添加的, 需要通过泛型参数声明。




 


<script setup lang="ts">
import { inject } from 'vue'

const injectName = inject<string>('name')
</script>
1
2
3
4
5

模板 ref

模板 ref 的类型定义可以通过泛型和 一个初始值 null 来声明。

<template>
  <div ref="devcursorRef">devcursor</div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const devcursorRef = ref<HTMLDivElement | null>(null)
</script>
1
2
3
4
5
6
7
8
9

注意

到组件被挂载前,这个 ref 的值都是初始的 null,在引用相关属性或方法时,最好结合可选链操作符(?.)。比如,上例中的 devcursorRef:devcursorRef.value?.innerHTML

几种常见的 HTML 元素 typescript 类型:

HTML 元素类型
divHTMLDivElement
imgHTMLImageElement
inputHTMLInputElement
spanHTMLSpanElement
tableHTMLTableElement
colHTMLTableColElement
selectHTMLSelectElement
一个无效的 HTML 元素HTMLUnknownElement

组件 ref

有时,你可能需要为一个子组件添加一个模板 ref,以便调用它公开的方法。

为了获取 MyModal 的类型,我们首先需要通过 typeof 得到其类型,再使用 TypeScript 内置的 InstanceType 工具类型来获取其实例类型:

DOM 事件处理器

在处理原生 DOM 事件时,应该为我们传递给事件处理器的参数正确地标注类型。







 
 
 


<template>
  <input type="text" @change="handleChange" />
</template>

<script setup lang="ts">

function handleChange(event: Event) {
  console.log((event.target as HTMLInputElement).value)
}
</script>
1
2
3
4
5
6
7
8
9
10

几种 vue 常见的事件处理器 typescript 类型:

事件名称事件标识事件类型
点击事件clickMouseEvent
键盘事件keyupMouseEvent

最常见的事件对象是 Event,Event 对象中,有个常用属性是 target,类型是 Event | null,然后大部分情况下,我们期望的 target 都不只是 Event,而是它的某个子类,比如 FileReader、Element等等,这种情况下就需要类型转换,去获取到你想要的属性。

function handleChange(event: Event) {
  console.log((event.target as HTMLInputElement).value)
  // 或者
  console.log((event.target as HTMLDivElement).value)
}
1
2
3
4
5
组合式 API 的类型声明 has loaded