
TypeScript 为 Vue 应用带来了强大的类型系统支持,Vue3 更是从底层开始使用 TypeScript 编写。本文将介绍 Vue3 中自带的 TypeScript 类型工具及其最佳实践,通过示例代码帮助开发者编写类型安全的 Vue 组件
一、基础组件类型
1.1 组件定义
使用 defineComponent 创建类型安全的组件:
import { defineComponent } from 'vue'
// 推荐使用 defineComponent 获得完整的类型推断
export default defineComponent({
setup() {
//自动推断出返回对象的类型
return {
message:'hello Vue3'
}
}
})1.2 Props 类型声明
使用 PropType 处理复杂类型:
import { defineComponent,PropType } from 'vue'
interface User{
id:number
name:string
age?:number
}
export default defineComponent({
props:{
// 基础类型
title:{
type:String,
required:true
},
// 复杂对象类型
userInfo:{
tyoe Object as PorpType<User>,
required:true
},
//数组类型
tags:{
type:Array as PropType<string[]>,
default:()=>[]
}
},
setup(props){
//自动推断出 props.title 为 string
console.log(props.title.toUpperCase())
//正确访问 User 类型的属性
console.log(props.userInfo.name)
}
})二、组合式 API 类型
2.1 Ref 类型
import { ref,Ref } from 'vue'
// 显式指定 Ref 类型(推荐)
const count: Ref<number>=ref(0)
//通过泛型初始化推断
const user = ref<User>({
id: 1,
name:'Alice'
})
//自动推断为 Ref<number>
const double = computed(()=> count.value * 2)2.2 Reactive 类型
import { reactive } from 'vue'
interface Formstate{
username:string
password: string
remember: boolean
}
// 使用接口定义 reactive 类型
const formState = reactive<FormState>({
username:'',
password:'',
remember: false
})三、组合式函数类型
3.1 自定义 Hook
import { ref, onMounted, Ref } from 'vue'
// 定义返回值类型
interface UseFetchResult<T>{
data: Ref<T | null>
error: Ref<Error | null>
loading: Ref<boolean>
}
export function useFetch<T>(url: string): UseFetchResult<T>{
const data = ref<T | null>(null)
const-error =ref<Error | null>(null)
const loading = ref(true)
onMounted(async()=>{
try {
const response = await fetch(url)
data.value = await response.json()
} catch(e){
error.value =e as Error
} finally {
loading.value = false
}
})
return {data, error, loading}
}四、组件通信类型
4.1 自定义事件
<script setup lang="ts">
// Child.vue
import { defineComponent } from 'vue'
export default defineComponent({
emits:{
// 验证 submit 事件
submit:(payload:{email:string; password:string })=>{
return payload.email.includes('@') && payload.password.length >= 6
}
},
setup(props,{emit }){
const handleSubmit =()=>{
emit('submit',{
email:'user@example.com',
password:'secret'
})
}
return { handleSubmit }
}
})
</script>
// Parent.vue
<template>
<Child @submit="handleSubmit" />
</template>
<script setup lang="ts">
const handleSubmit =(payload:{ email: string; password: string })=> {
console.log('Received:', payload)
}
</script>4.2 模板引用类型
// 引用 DOM 元素
const inputRef = ref<HTMLInputElement | null>(null)
//引用子组件实例
const childComponent = ref<InstanceType<typeof childComponent>| null>(null)
onMounted(()=> {
inputRef.value?.focus()
childComponent.value?.someMethod()
})五、进阶类型技巧
5.1 全局属性扩展
// main.ts
import { createApp } from 'vue'
declare module 'vue'{
interface ComponentCustomProperties{
$filters:{
currency(value:number):string
}
}
}
const app = createApp(App)
app.config.globalProperties.$filters = {
currency(value:number){
return`$${value.toFixed(2)}`
}
}5.2 类型化 Provide/Inject
import {inject, provide } from 'vue'
interface UserContext{
id: number
name: string
}
const symbol =Symbol() as InjectionKey<UserContext>
// 父组件
provide(symbol,{
id: 1,
name:'Alice
})
// 子组件
const user =inject(symbol)//类型为 Usercontext | undefined









