Vue 3配上TypeScript,那真是天生一对。Composition API的设计思路,跟用TS写逻辑简直是严丝合缝。今天咱不扯理论,就说说实际写代码时,那些真正有用的小细节。
![图片[1]-如何在Vue 3项目中使用TypeScript?-速码派](http://www.sumapai.com/wp-content/uploads/2026/01/a40ab7af4b8d41c9a66968926e07566a_tplv-tb4s082cfz-aigc_resize_1080_1080-1024x683.webp)
用<script setup>语法糖,现在是主流写法了。你只需要在script标签上加个lang="ts"和setup属性,门就开了。定义props得用defineProps这个编译器宏,它的参数直接就是一个类型声明:
<script setup lang="ts">
interface Props {
title: string;
count?: number;
}
const props = defineProps<Props>();
</script>
看,多直接。连默认值都能通过withDefaults这个辅助宏来搞定:
const props = withDefaults(defineProps<Props>(), {
count: 0
});
事件定义用defineEmits,也可以用类型字面量来声明,智能提示一下就有了:
const emit = defineEmits<{
(e: 'update:title', value: string): void;
(e: 'confirm'): void;
}>();
在setup里写响应式数据,ref和reactive的类型处理有点小区别。ref推断类型很聪明,你给个初始值它就明白了:
const count = ref(0); // 自动推断为 Ref<number>
但如果你声明的时候不给值,或者值可能为null,就得显式传个泛型参数:
const user = ref<User | null>(null);
用reactive的时候,它会对整个对象进行“深度响应式”包装,类型推断一般很准,但你最好也给它约束一个接口:
interface FormState {
name: string;
age: number;
}
const form = reactive<FormState>({
name: '',
age: 18
});
计算属性computed的类型通常自动从返回值推导出来,很省心。但如果你写的计算属性逻辑分支复杂,手动标注一下返回类型会更稳妥。
在Vue组件里引用一个DOM元素,用ref配合类型标注。这跟React里的useRef很像:
const inputEl = ref<HTMLInputElement | null>(null);
模板ref数组的类型稍微麻烦点,但你把它声明为(Element | ComponentPublicInstance)[]基本就能覆盖大多数情况。
用Pinia管理状态,类型支持好得让人感动。定义store时,state、getters、actions都能被很好地推断。你几乎不需要额外写类型,但为state定义一个接口会让结构更清晰:
interface UserState {
list: User[];
}
export const useUserStore = defineStore('user', {
state: (): UserState => ({ list: [] }),
getters: {
userNameList: (state) => state.list.map(u => u.name)
},
actions: {
async fetchUsers() {
this.list = await api.getUsers();
}
}
});
在组件里直接用这个store,userStore.list、userStore.userNameList的类型都是对的,连actions里的this都帮你推断好了。
最后提醒个小坑。有些第三方Vue库如果没提供类型,你可能需要在shims-vue.d.ts里用declare module给它补上。路由和Vue本身的核心类型一般没问题,但自己写的工具函数,记得做好导出和导入的类型声明。
Vue 3 + TS的体验是越用越顺手的,关键在于开始的时候别怕写那两个接口定义。前期多花三十秒,后期能省三十分钟查bug的时间。


























暂无评论内容