一、为 props 标注类型
使用 <script setup>
方式一:当使用 <script setup>
时,defineProps()
宏函数支持从它的参数中推导类型:
const props = defineProps({
treeTableProps: {
type: Array,
default: null,
required: false
},
msg: {
type: String,
required: false
}
})
// 使用
console.log(props.msg)
方式二:通过泛型参数来定义 props 的类型,这种方式更加直接
interface T {
prop: string,
label: string,
width: number,
children: Array<T>
}
const props = defineProps<{
msg?: string,
treeTableProps: Array<T>,
}>()
或者通过ts的接口interface简写一下:
// 方式三
interface T {
prop: string,
label: string,
width: number,
children: Array<T>
}
interface params {
msg?: string,
treeTableProps: Array<T>,
}
const props2 = defineProps<params>()
这被称为 基于类型的声明
,编译器会尽可能地尝试根据类型参数推导出等价的运行时选项。这种方式的不足之处在于,失去了定义 props 默认值的能力。
为了可以给参数设置默认值,我们可以使用 withDefaults
编译器宏:
interface T {
prop: string,
label: string,
width: number,
children?: Array<T>
}
interface params {
msg?: string,
treeTableProps: Array<T>,
}
const props = withDefaults(defineProps<{
msg?: string,
treeTableProps: Array<T>,
}>(), {
msg: '我是默认值',
})
//or
const props = withDefaults(defineProps<params>(), {
msg: '我是默认值',
})
二、为 emits 标注类型
在 <script setup>
中,emit 函数的类型标注也可以使用 运行时声明
或者 基于类型的声明
:
//子组件
const emit = defineEmits(['receiveData'])
function cellClick(row: any) {
emit('receiveData', row)
}
//父组件
<Index @receiveData="receiveData" :treeTableProps="treeTableProps"></Index>
//接收数据
let childData = ref<any>()
function receiveData(row: object) {
childData.value = row
}
三、为 ref() 标注类型
默认推导类型
ref 会根据初始化时的值自动推导其类型:
// 推导出的类型:Ref<number>
const year = ref(2020)
// => TS Error: Type 'string' is not assignable to type 'number'.
year.value = '2020'
通过接口指定类型
有时我们可能想为 ref 内的值指定一个更复杂的类型,可以通过使用 Ref
这个接口:
import type { Ref } from 'vue'
import { ref } from 'vue'
// 通过Ref接口指定类型
const year: Ref<string | number> = ref('2023')
year.value = 2023//成功
通过泛型指定类型
或者,在调用 ref() 时传入一个泛型参数,来覆盖默认的推导行为:
// 得到的类型:Ref<string | number>
const year = ref<string | number>('2020')
year.value = 2020 // 成功!
如果你指定了一个泛型参数但没有给出初始值,那么最后得到的就将是一个包含 undefined 的联合类型:
// 推导得到的类型:Ref<number | undefined>
const n = ref<number>()
四、为 reactive() 标注类型
默认推导类型
// 默认推导 推导得到的类型:{ str: string }
const str = reactive({ str: '122' })
通过接口指定类型
// 通过接口指定类型
interface obj {
name: string,
age: number
}
const myObj: obj = reactive({ name: 'suosuo', age: 20 })
五、为 computed() 标注类型
默认推导类型
computed()
会自动从其计算函数的返回值上推导出类型:
import { ref, reactive, computed } from 'vue'
const count = ref(0)
// 推导得到的类型:ComputedRef<number>
const value = computed(() => count.value * 2)
通过泛型指定类型
你还可以通过泛型参数显式指定类型:
const value = computed<number>(() =>
count.value * 2 // 若返回值不是number类型就会报错
)
六、为事件处理函数标注类型
<template>
<input type="text" @change="handleChange" />
</template>
// 为事件处理函数标注类型
function handleChange(event: Event) {
console.log((event.target as HTMLInputElement).value)
}
没有类型标注时,这个 event
参数会隐式地标注为 any
类型。就会有提示,因此,建议显式地为事件处理函数的参数标注类型。如上面代码所示
七、为组件模板引用标注类型
假设存在一个模态框,通过在父组件触发该组件的open函数来显示该页面的内容。
注意:当我们想要从父组件中调用子组件方法时,需要将该方法在子组件中通过defineExpose暴露出来,否则无法调用。
<template>
<div class='main'>
<h2 v-if="isShowModal">我的模态框的内容</h2>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
const isShowModal = ref(false)
const open = () => (isShowModal.value = true)
defineExpose({
open,
});
</script>
此时我们需要为一个子组件添加一个模板 ref,以便调用它公开的方法。(vue2中我们是通过给子组件设置ref属性,然后通过this.$refs.xxx.methods()来实现的),那这里如何实现呢?
为了获取 Modal
的类型,我们首先需要通过 typeof
得到其类型,再使用 TypeScript 内置的 InstanceType
工具类型来获取其实例类型:
父组件:
<template>
<button @click="showModal">显示模态框</button>
<Modal ref="modalRef"></Modal>
</template>
<script lang="ts" setup>
import { getCurrentInstance, onMounted, ref } from 'vue'
import Modal from '@/components/modal.vue'
const modalRef = ref<InstanceType<typeof Modal> | null>(null)
const showModal = () => {
modalRef.value?.open()
}
</script>
注意:子组件的ref值应该和下面定义的值保持一致,如:modalRef
看点击按钮之后的效果:
如何在 vue3 组件中使用 TS 类型的讲解就到此结束啦,有写的不对的地方,欢迎评论区指出哦~