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