外观风格
组合式 API 类型声明
组合式的类型声明主要集中在:
- 相关的
API
; - 对 HTML 和组件的
ref
引用; - 事件;
ref 类型声明
有3种方式对 ref
进行类型声明
- 泛型
<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
2
3
4
5
6
7
interface
或type
对于复杂的数据类型,比如对象或者数组,可以使用 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
2
3
4
5
6
7
8
reactive 类型声明
reactive 类型声明有两种方式。
- 直接使用
interface
或者type
- 通过泛型参数的形式增加类型
<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
2
3
4
5
6
7
8
9
10
提示
Vue 官方不推荐使用 reactive() 的泛型参数,因为处理了深层次 ref 解包的返回值与泛型参数的类型不同。
computed 类型声明
computed 类型声明有两种方式。
- 自动推导
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
2
3
4
5
6
7
8
9
10
- 通过泛型参数显式指定类型
<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
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
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
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
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
2
3
4
5
6
7
8
9
注意
到组件被挂载前,这个 ref 的值都是初始的 null
,在引用相关属性或方法时,最好结合可选链操作符(?.)
。比如,上例中的 devcursorRef:devcursorRef.value?.innerHTML
。
几种常见的 HTML 元素 typescript 类型:
HTML 元素 | 类型 |
---|---|
div | HTMLDivElement |
img | HTMLImageElement |
input | HTMLInputElement |
span | HTMLSpanElement |
table | HTMLTableElement |
col | HTMLTableColElement |
select | HTMLSelectElement |
一个无效的 HTML 元素 | HTMLUnknownElement |
组件 ref 类型声明
有时,你可能需要为一个子组件添加一个模板 ref,以便调用它公开的方法。
为了获取 MyModal
的类型,我们首先需要通过 typeof
得到其类型,再使用 TypeScript 内置的 InstanceType
工具类型来获取其实例类型:
事件类型声明
在处理原生 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
2
3
4
5
6
7
8
9
10
几种 vue 常见的事件处理器的 typescript
类型:
事件名称 | 事件标识 | 事件类型 |
---|---|---|
点击事件 | click | MouseEvent |
键盘事件 | keyup | MouseEvent |
最常见的事件对象是 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
2
3
4
5