什么时候需要这么做
接手了一个 Vue 3 项目,代码是 Webpack 构建的(基于 @vue/cli),当初创建时没勾选 TypeScript。现在想把 TS 加进去,逐步把 .vue 文件里 <script> 改成 <script lang="ts">。
新项目当然推荐直接用 Vite + TypeScript 一气呵成 —— Webpack 启动等 3-4 秒、HMR 几百毫秒,Vite 这两项都是 0.1 秒级别。但这是篇老项目改造笔记,目标是不重建项目的前提下加 TS 支持。
方法 1:@vue/cli 提供的一键加 TS
项目根目录运行:
vue add @vue/typescript
会自动:
- 安装
typescript+@vue/cli-plugin-typescript到devDependencies - 生成
tsconfig.json - 把
main.js改成main.ts - 新增
src/shims-vue.d.ts(让 TS 能识别.vue文件) - 更新 webpack 入口配置
过程中会有几个交互问题,默认一路 Y 即可,如果有别的偏好(class-style components / TSLint)按情况选。

装完后 package.json 大概长这样:
{
"name": "xshop-ui",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"axios": "^1.3.4",
"core-js": "^3.6.5",
"lib-flexible": "^0.3.2",
"pinia": "^2.0.13",
"postcss-px2rem": "^0.3.0",
"vant": "^3.4.3",
"vue": "^3.0.0",
"vue-class-component": "^8.0.0-0",
"vue-router": "^4.1.6",
"vuex": "^4.0.0-0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.19",
"@vue/cli-plugin-router": "~4.5.19",
"@vue/cli-plugin-typescript": "~4.5.19",
"@vue/cli-plugin-vuex": "~4.5.19",
"@vue/cli-service": "~4.5.19",
"@vue/compiler-sfc": "^3.0.0",
"babel-plugin-import": "^1.13.6",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"prettier": "2.8.4",
"typescript": "~4.1.5"
}
}
VS Code 配置(关键的一步)
VS Code 默认对 Vue 文件用 Vetur 解析,但 Vetur 对 Vue 3 + TS 支持不好。必须禁用 Vetur,改装 Volar。

步骤:
- 打开扩展面板,搜 "Vetur",点禁用(项目级或全局都行)
- 搜 "Vue Language Features (Volar)",装上
- (可选)搜 "TypeScript Vue Plugin (Volar)",装上 —— 给
.ts文件里 import.vue时也提供类型提示 - 重启 VS Code(
Developer: Reload Window)

2024 年后 Volar 升级成了 Vue Official(Vue.volar),新版本更稳。如果你用 Vue 3.3+,装这个新版的就好。
tsconfig.json 推荐配置
vue add @vue/typescript 生成的 tsconfig 比较保守,实际项目里建议加这些:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"baseUrl": ".",
"types": ["webpack-env"],
"paths": {
"@/*": ["src/*"]
},
"lib": ["ES2020", "DOM", "DOM.Iterable"]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": ["node_modules"]
}
strict: true 是 TS 的精髓,但老项目突然全开会一堆报错。如果想渐进迁移,先这样:
{
"strict": false,
"noImplicitAny": false,
"strictNullChecks": false
}
然后随着把代码逐步从 .js 改成 .ts,再把这几项一个个打开。
把类型集中管理,别散在组件里
项目里类型(interface、type)如果都写在 .vue 文件的 <script> 里,过段时间就会变成一堆复制粘贴的同名类型。最好集中收纳:

推荐目录结构:
src/
├── types/
│ ├── api.ts # 接口请求/响应类型
│ ├── user.ts # 业务实体:用户
│ ├── product.ts # 业务实体:商品
│ └── index.ts # 集中 re-export
├── api/
│ └── user.ts # 接口请求函数,引用 ../types/user
└── views/
└── UserList.vue # 引用 @/types
src/types/index.ts:
export * from './api'
export * from './user'
export * from './product'
src/types/user.ts:
export interface User {
id: number
name: string
email: string
avatar?: string
createdAt: string
}
export type UserRole = 'admin' | 'editor' | 'viewer'
export interface UserWithRole extends User {
role: UserRole
}
组件里使用:
<script setup lang="ts">
import type { User, UserRole } from '@/types'
import { fetchUsers } from '@/api/user'
import { ref } from 'vue'
const users = ref<User[]>([])
const currentRole = ref<UserRole>('viewer')
const load = async () => {
users.value = await fetchUsers()
}
</script>
这样有几个好处:
- 同一种类型只定义一次,不会出现"同名 interface 多版本并存"
- 后端接口变了,只改
src/types一处,组件不动 - 新人看项目,看
src/types就知道有哪些核心实体
推荐 TS 学习资料
这块改造完之后,如果团队成员对 TS 不熟,推荐去 B 站找系统教程:
建议优先掌握:基础类型、interface、type、泛型、工具类型(Partial / Pick / Omit / Record 等)。这几块覆盖了 90% 实际代码里会用到的 TS 用法,够用了。
—— 别看了 · 2026