与 TypeScript 的深度整合
TypeScript 作为 JavaScript 的超集,为 Vue 3 项目提供了类型安全和更好的开发体验。Vue 3 从底层设计上优化了对 TypeScript 的支持,尤其在 Composition API 和生态工具(如 Vite、Pinia)的配合下,实现了深度整合。本节将详细讲解如何在 Vue 3 中使用 TypeScript,涵盖配置、组件编写和状态管理,并通过示例展示其实际应用,帮助你打造类型安全的现代应用。
为什么使用 TypeScript?
- 类型安全:捕获潜在错误,提升代码可靠性。
- 开发效率:智能提示和自动补全加速编码。
- 团队协作:类型定义作为文档,减少沟通成本。
- 生态支持:Vue 3 核心及主流库(如 Pinia、Vue Router)原生支持。
配置 TypeScript
初始化项目
使用 Vite 创建带 TypeScript 的 Vue 项目:
npm create vite@latest my-ts-app --template vue-ts
cd my-ts-app
npm install
项目结构
my-ts-app/
├── src/
│ ├── main.ts # TS 入口文件
│ ├── App.vue # 根组件
│ ├── vite-env.d.ts # 环境声明
│ └── shims-vue.d.ts # Vue 文件类型声明(可选)
├── tsconfig.json # TypeScript 配置
├── vite.config.ts # Vite 配置
└── package.json
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*", "vite.config.ts"],
"exclude": ["node_modules", "dist"]
}
vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': '/src'
}
}
});
组件中的 TypeScript
基本用法
App.vue
<template>
<h1>{{ title }}</h1>
<Counter :initial="10" />
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import Counter from './Counter.vue';
export default defineComponent({
components: { Counter },
setup() {
const title = ref<string>('Vue 3 with TypeScript');
return { title };
}
});
</script>
Counter.vue
<template>
<div>
<p>计数: {{ count }}</p>
<button @click="increment">增加</button>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
props: {
initial: {
type: Number,
default: 0
}
},
setup(props) {
const count = ref<number>(props.initial);
const increment = () => count.value++;
return { count, increment };
}
});
</script>
- 效果:显示标题和计数器,点击增加计数。
- 解析:
lang="ts":启用 TypeScript。defineComponent:提供类型推导支持。- 类型注解(如
string、number)增强安全性。
类型定义
Props 类型
<script lang="ts">
import { defineComponent, PropType } from 'vue';
interface User {
id: number;
name: string;
}
export default defineComponent({
props: {
user: {
type: Object as PropType<User>,
required: true
}
},
setup(props) {
return { userName: props.user.name };
}
});
</script>
- 效果:接收
User类型对象,访问属性有类型提示。
自定义事件
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
emits: {
'update:value': (value: number) => typeof value === 'number'
},
setup(props, { emit }) {
const increment = () => emit('update:value', 42);
return { increment };
}
});
</script>
- 效果:确保事件参数类型正确。
与 Pinia 的整合
Store 定义
// src/stores/counter.ts
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useCounterStore = defineStore('counter', () => {
const count = ref<number>(0);
const increment = () => count.value++;
return { count, increment };
});
使用
<template>
<p>计数: {{ store.count }}</p>
<button @click="store.increment">增加</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { useCounterStore } from '@/stores/counter';
export default defineComponent({
setup() {
const store = useCounterStore();
return { store };
}
});
</script>
- 效果:类型安全的 Store 操作。
与 Vue Router 的整合
路由配置
// src/router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [
{ path: '/', component: () => import('@/views/Home.vue') },
{ path: '/about', component: () => import('@/views/About.vue') }
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
使用
<script lang="ts">
import { defineComponent } from 'vue';
import { useRouter, useRoute } from 'vue-router';
export default defineComponent({
setup() {
const router = useRouter();
const route = useRoute();
const goToAbout = () => router.push('/about');
return { path: route.path, goToAbout };
}
});
</script>
- 效果:类型化的路由操作。
高级用法
1. 类型推导增强
自定义 Hook
// src/hooks/useCounter.ts
import { ref, Ref } from 'vue';
export function useCounter(initial: number): { count: Ref<number>, increment: () => void } {
const count = ref(initial);
const increment = () => count.value++;
return { count, increment };
}
<script lang="ts">
import { defineComponent } from 'vue';
import { useCounter } from '@/hooks/useCounter';
export default defineComponent({
setup() {
const { count, increment } = useCounter(0);
return { count, increment };
}
});
</script>
2. 类型声明文件
shims-vue.d.ts(可选)
declare module '*.vue' {
import { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
}
- 作用:为
.vue文件提供类型支持。
实践:完整示例
组件与 Store
// src/stores/user.ts
import { defineStore } from 'pinia';
import { ref } from 'vue';
interface User {
id: number;
name: string;
}
export const useUserStore = defineStore('user', () => {
const users = ref<User[]>([]);
const addUser = (user: User) => users.value.push(user);
return { users, addUser };
});
<!-- src/App.vue -->
<template>
<div>
<input v-model="newUser" @keyup.enter="addUser" placeholder="输入用户名" />
<ul>
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { useUserStore } from '@/stores/user';
export default defineComponent({
setup() {
const userStore = useUserStore();
const newUser = ref<string>('');
const addUser = () => {
if (newUser.value.trim()) {
userStore.addUser({ id: Date.now(), name: newUser.value });
newUser.value = '';
}
};
return { users: userStore.users, newUser, addUser };
}
});
</script>
- 效果:类型安全的用户列表管理。
注意事项
- 严格模式:
strict: true可能增加类型检查负担,初期可关闭部分选项。
- Props 复杂类型:
- 使用
PropType处理对象或数组。
- 使用
- IDE 支持:
- 使用 VS Code + Volar 插件优化体验。
总结
Vue 3 与 TypeScript 的深度整合通过 Composition API 和生态工具实现了类型安全和高效率。无论是组件 Props、Pinia Store 还是 Vue Router,都能享受类型推导和智能提示的好处。本节的实践为你提供了完整的 TypeScript 配置和使用方法,下一章将探讨性能优化,进一步提升你的 Vue 3 技能!
