Vue2 + TypeScript 核心是用装饰器(class 语法)或Vue.extend 写组件,配合vue-class-component 与vue-property-decorator提供类型与装饰器支持Vue.js。下面从环境搭建→组件写法→Props / 生命周期→Vuex / 路由→常见坑,给你一套完整可落地教程。
一、环境搭建
1:Vue CLI 直接创建
bash
# 安装/更新 CLI
npm install -g @vue/cli
# 创建项目
vue create vue2-ts-demo
# 选择:Manually select features → 勾选 TypeScript → 选择 Vue 2.x
# 后续可默认,创建完成后进入目录
cd vue2-ts-demo
npm run serve
生成关键文件:
tsconfig.json:TS 编译配置src/shims-vue.d.ts:让 TS 识别.vue文件src/shims-tsx.d.ts:支持 TSX 语法
2:现有 Vue2 项目接入 TS
安装依赖
bash
npm install typescript ts-loader --save-dev
npm install vue-class-component vue-property-decorator --save
配置 tsconfig.json(根目录)
bash
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"strict": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "node"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
配置 vue.config.js(支持 TS 加载)
bash
module.exports = {
chainWebpack: config => {
config.resolve.extensions.add('.ts').add('.tsx')
config.module
.rule('ts')
.test(/\.(ts|tsx)$/)
.use('ts-loader')
.loader('ts-loader')
.options({ appendTsSuffixTo: [/\.vue$/] })
}
}
类型声明文件
bash
// src/shims-vue.d.ts
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
二、组件写法(Class + 装饰器(@Component/@Prop/@Computed))
1. 基础组件(@Component)
bash
<!-- src/components/Hello.ts -->
<template>
<div>
<h1>{{ msg }}</h1>
<button @click="sayHello">点击</button>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
@Component
export default class Hello extends Vue {
// 数据:直接声明类型+初始值
msg: string = 'Hello Vue2 + TS'
// 方法:直接写,自动绑定 this
sayHello(): void {
alert(this.msg)
}
}
</script>
- Props 类型(
@Prop)
bash
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import { Prop } from 'vue-property-decorator'
@Component
export default class User extends Vue {
// 基础类型
@Prop() id: number
// 带默认值
@Prop({ default: '匿名' }) name: string
// 必传+校验
@Prop({ type: String, required: true }) gender!: string
}
</script>
- 计算属性(
@Computed)
bash
import { Computed } from 'vue-property-decorator'
@Component
export default class User extends Vue {
firstName: string = '张'
lastName: string = '三'
@Computed()
get fullName(): string {
return this.firstName + this.lastName
}
}
4. 生命周期(直接写方法)
bash
@Component
export default class Hello extends Vue {
created(): void {
console.log('组件创建')
}
mounted(): void {
console.log('组件挂载')
}
}
三、Vue.extend 写法(无装饰器)
适合不想用装饰器的场景:
bash
import Vue from 'vue'
export default Vue.extend({
data() {
return { msg: 'Hello' as string }
},
methods: {
greet(name: string): string {
return `Hi ${name}`
}
}
})
四、Vuex 与 TypeScript
1. 定义 State
bash
// src/store/index.ts
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
interface State {
count: number
user: { name: string; age: number }
}
export default new Vuex.Store<State>({
state: {
count: 0,
user: { name: '李四', age: 20 }
},
mutations: {
ADD_COUNT(state) {
state.count++
}
}
})
- 组件中使用 Vuex
bash
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import { mapState, mapMutations } from 'vuex'
@Component({
computed: { ...mapState(['count', 'user']) },
methods: { ...mapMutations(['ADD_COUNT']) }
})
export default class Counter extends Vue {
// 直接使用 this.count / this.user
}
</script>
五、路由与 TypeScript
bash
// src/router/index.ts
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home,
meta: { title: '首页' } // 可扩展类型
}
]
})
六、常见问题与避坑
- this 隐式 any :
tsconfig.json开启strict: trueVue.js - 找不到 .vue 模块 :检查
shims-vue.d.ts是否正确声明 - 装饰器报错 :确保
experimentalDecorators: true - Props 类型不生效 :使用
@Prop装饰器而非原生写法Vue.js