TypeScript 集成

下面,我们来系统的梳理关于 Vue + TypeScript 深度集成 的基本知识点:


一、TypeScript 与 Vue 集成概述

1.1 为什么需要 TypeScript

  • 类型安全:编译时类型检查,减少运行时错误
  • 代码智能:强大的IDE智能提示和自动补全
  • 可维护性:清晰的接口定义和类型约束
  • 团队协作:统一的代码规范和接口约定
  • 重构信心:安全地进行大规模代码重构

1.2 Vue 与 TypeScript 集成方式

集成方式适用场景特点
选项式API传统Vue项目迁移兼容性好,学习曲线平缓
组合式API新项目,复杂逻辑更好的类型推断,更灵活
Class API面向对象背景开发者Vue 2主流方式,Vue 3可选
<script setup>现代Vue开发最简洁的语法,最佳类型支持

二、基础环境配置

2.1 创建支持 TypeScript 的 Vue 项目

使用 Vite 创建:
npm create vite@latest my-vue-ts-app -- --template vue-ts
使用 Vue CLI 创建:
vue create my-vue-ts-app
# 选择 Manually select features → 勾选 TypeScript

2.2 关键配置文件

tsconfig.json
{"compilerOptions": {"target": "ESNext","module": "ESNext","strict": true,"jsx": "preserve","moduleResolution": "node","esModuleInterop": true,"skipLibCheck": true,"forceConsistentCasingInFileNames": true,"baseUrl": ".","paths": {"@/*": ["src/*"]},"types": ["vite/client"],"lib": ["ESNext", "DOM", "DOM.Iterable"]},"include": ["src/**/*.ts","src/**/*.d.ts","src/**/*.tsx","src/**/*.vue"],"exclude": ["node_modules"]
}
vite.config.ts (Vite 项目)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'url'export default defineConfig({plugins: [vue()],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}},server: {port: 8080}
})

三、组件开发模式

3.1 组合式API + <script setup>

<script setup lang="ts">
import { ref, computed } from 'vue'// Props 类型定义
interface Props {title: stringcount?: number
}const props = defineProps<Props>()// 事件声明
const emit = defineEmits<{(e: 'update:count', value: number): void
}>()// 响应式数据
const message = ref<string>('Hello TS!')// 计算属性
const reversedMessage = computed(() => {return message.value.split('').reverse().join('')
})// 方法
const increment = () => {emit('update:count', (props.count || 0) + 1)
}
</script><template><div><h1>{{ title }}</h1><p>{{ message }} → {{ reversedMessage }}</p><button @click="increment">Count: {{ count || 0 }}</button></div>
</template>

3.2 选项式API类型支持

<script lang="ts">
import { defineComponent } from 'vue'export default defineComponent({props: {title: {type: String,required: true},count: {type: Number,default: 0}},emits: ['update:count'],data() {return {message: 'Hello TS!' as string}},computed: {reversedMessage(): string {return this.message.split('').reverse().join('')}},methods: {increment(): void {this.$emit('update:count', this.count + 1)}}
})
</script>

四、类型系统增强

4.1 全局类型声明

声明全局属性
// src/types/index.d.ts
import { Router } from 'vue-router'declare module '@vue/runtime-core' {interface ComponentCustomProperties {$router: Router$translate: (key: string) => string}
}
扩展全局组件类型
declare module '@vue/runtime-core' {export interface GlobalComponents {RouterLink: typeof import('vue-router')['RouterLink']RouterView: typeof import('vue-router')['RouterView']BaseButton: typeof import('./components/BaseButton.vue')['default']}
}

4.2 复杂类型工具

使用泛型约束 Props
import { PropType } from 'vue'interface User {id: numbername: stringemail: string
}export default defineComponent({props: {user: {type: Object as PropType<User>,required: true},permissions: {type: Array as PropType<('read' | 'write' | 'delete')[]>,default: () => ['read']}}
})
条件类型
type ButtonVariant = 'primary' | 'secondary' | 'text'
type ButtonSize = 'small' | 'medium' | 'large'interface ButtonProps {variant?: ButtonVariantsize?: ButtonSizedisabled?: boolean
}// 基于 Props 推导事件类型
type ButtonEmits = {click: [event: MouseEvent]hover: [isHovering: boolean]
}

五、状态管理与类型安全

5.1 Pinia 状态管理

类型化 Store
// stores/user.ts
import { defineStore } from 'pinia'interface User {id: numbername: stringemail: string
}interface UserState {currentUser: User | nullisAuthenticated: boolean
}export const useUserStore = defineStore('user', {state: (): UserState => ({currentUser: null,isAuthenticated: false}),actions: {async login(credentials: { email: string; password: string }) {const response = await api.login(credentials)this.currentUser = response.userthis.isAuthenticated = true},logout() {this.currentUser = nullthis.isAuthenticated = false}},getters: {username: (state) => state.currentUser?.name || 'Guest'}
})

5.2 Vuex 类型增强 (Vue 2)

import { createStore } from 'vuex'interface State {count: numberuser: User | null
}const store = createStore<State>({state: {count: 0,user: null},mutations: {setUser(state, payload: User) {state.user = payload},increment(state) {state.count++}},actions: {async fetchUser({ commit }, id: number) {const user = await api.getUser(id)commit('setUser', user)}},getters: {doubleCount: state => state.count * 2}
})

六、路由系统类型化

6.1 Vue Router 类型集成

import { createRouter, createWebHistory } from 'vue-router'// 定义路由元信息类型
declare module 'vue-router' {interface RouteMeta {requiresAuth?: booleantitle: string}
}const router = createRouter({history: createWebHistory(),routes: [{path: '/',component: () => import('@/views/Home.vue'),meta: { title: 'Home' }},{path: '/profile',component: () => import('@/views/Profile.vue'),meta: { requiresAuth: true,title: 'User Profile' }},{path: '/:pathMatch(.*)*',component: () => import('@/views/NotFound.vue'),meta: { title: 'Page Not Found' }}]
})// 导航守卫中使用类型
router.beforeEach((to, from) => {if (to.meta.requiresAuth && !isAuthenticated()) {return '/login'}
})

七、高级类型技巧

7.1 泛型组件

<script setup lang="ts" generic="T">
import { ref } from 'vue'defineProps<{items: T[]selected: T
}>()defineEmits<{(e: 'select', item: T): void
}>()
</script><template><ul><li v-for="item in items" :key="item.id"@click="$emit('select', item)">{{ item }}</li></ul>
</template>

7.2 类型安全的模板引用

<script setup lang="ts">
import { ref } from 'vue'const inputRef = ref<HTMLInputElement | null>(null)const focusInput = () => {inputRef.value?.focus()
}
</script><template><input ref="inputRef" type="text"><button @click="focusInput">Focus Input</button>
</template>

7.3 条件渲染类型收窄

interface User {id: numbername: string
}const user = ref<User | null>(null)// 使用类型守卫
function isUser(user: User | null): user is User {return user !== null
}// 在模板中使用
<template><div v-if="isUser(user)"><!-- 此处 user 类型为 User --><h1>{{ user.name }}</h1></div><div v-else>Loading...</div>
</template>

八、测试策略

8.1 组件单元测试

import { mount } from '@vue/test-utils'
import Counter from '@/components/Counter.vue'describe('Counter.vue', () => {it('emits increment event when clicked', async () => {const wrapper = mount(Counter, {props: {initialCount: 5}})await wrapper.find('button').trigger('click')expect(wrapper.emitted()).toHaveProperty('increment')expect(wrapper.find('button').text()).toContain('6')})
})

8.2 类型测试

// 使用 tsd 进行类型测试
import { expectType } from 'tsd'
import { useUserStore } from '@/stores/user'const store = useUserStore()// 测试 state 类型
expectType<number>(store.count)
expectType<User | null>(store.user)// 测试 getter 类型
expectType<string>(store.username)// 测试 action 类型
expectType<(credentials: { email: string; password: string }) => Promise<void>>(store.login)

九、性能优化

9.1 类型导入优化

// 使用类型导入减少运行时开销
import type { Router } from 'vue-router'function useNavigation(router: Router) {// ...
}

9.2 避免 any 类型

// 使用 unknown 替代 any
function safeParse(data: string): unknown {return JSON.parse(data)
}// 使用类型守卫
function isUser(data: unknown): data is User {return typeof data === 'object' && data !== null && 'id' in data && 'name' in data
}// 使用类型断言
const userData = safeParse(localStorage.getItem('user') || '{}') as User

十、实践

10.1 项目结构组织

src/
├── assets/
├── components/
│   ├── ui/
│   └── business/
├── composables/         # 组合式函数
├── layouts/
├── router/
├── stores/
├── types/               # 全局类型声明
│   ├── api.d.ts
│   ├── components.d.ts
│   └── index.d.ts
├── utils/               # 工具函数
├── views/
├── App.vue
└── main.ts

10.2 自定义 ESLint 规则

// .eslintrc.js
module.exports = {rules: {'@typescript-eslint/no-explicit-any': 'error','@typescript-eslint/explicit-function-return-type': ['error',{allowExpressions: true}],'vue/require-typed-props': 'error','vue/require-typed-emits': 'error'}
}

十一、常见问题解决

11.1 第三方库类型缺失

# 安装社区维护的类型声明
npm install -D @types/lodash# 对于无类型声明的库
// src/shims.d.ts
declare module 'untyped-module' {const content: anyexport default content
}

11.2 模板事件处理类型

<script setup lang="ts">
const handleChange = (e: Event) => {// 类型收窄if (e.target instanceof HTMLInputElement) {console.log(e.target.value)}
}
</script><template><input type="text" @input="handleChange">
</template>

11.3 全局组件类型扩展

// src/types/components.d.ts
import type { DefineComponent } from 'vue'declare module 'vue' {export interface GlobalComponents {BaseButton: DefineComponent<{variant?: 'primary' | 'secondary'size?: 'small' | 'medium' | 'large'}>Icon: DefineComponent<{name: stringsize?: number}>}
}

十二、总结

Vue与TypeScript深度集成要点:

  1. 正确配置:搭建支持TS的Vue环境
  2. 组件开发:优先使用<script setup>语法
  3. 类型增强:扩展全局类型和组件类型
  4. 状态管理:类型安全的Pinia/Vuex
  5. 路由系统:类型化的Vue Router配置
  6. 高级技巧:泛型组件、条件类型等
  7. 测试策略:单元测试与类型测试结合
  8. 性能优化:避免any,使用类型导入
基础配置
组件开发
类型增强
状态管理
路由系统
高级技巧
测试策略
性能优化
生产部署

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88117.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88117.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

npm proxy

背景 前端项目下载依赖时经常会出现timeout的情况&#xff0c;此时有三种解决方案。 切换镜像源。 适用于对依赖版本要求不严格的情况。延长超时时间。设置npm proxy。一些生产环境对依赖版本有着严格要求&#xff0c;并且指定了依赖的下载地址&#xff08;如下图&#xff09;&…

TVS管工作原理是什么?主要的应用场景都有哪些?

什么是TVS管&#xff1f; TVS&#xff08;Transient Voltage Suppressors&#xff09;&#xff0c;即瞬态电压抑制器&#xff0c;也被称为雪崩击穿二极管&#xff0c;是一种二极管形式的高效能保护器件&#xff0c;常用来防止端口瞬间的电压冲击造成后级电路的损坏。 TVS 有单…

分布式微服务系统架构第156集:JavaPlus技术文档平台日更-Java线程池使用指南

title: java线程池使用 author: 哪吒 date: 2023-06-15点击勘误issues&#xff0c;哪吒感谢大家的阅读Java线程池使用指南1. 线程池基础使用1.1 创建线程池的方式方式一&#xff1a;使用Executors工具类&#xff08;不推荐&#xff09;// 1. 固定大小线程池 ExecutorService fi…

【最新版】点大全能版v2.6.7.1 含汇付斗拱插件+uniapp前端

一.介绍V2全能版本、独立版本全开源&#xff0c;含链动21&#xff0c;汇付斗拱​、排队免单、推三返1 &#xff0c;扶持金&#xff0c;平级奖&#xff0c;团队业绩奖&#xff0c;酒店管理&#xff0c;约车&#xff0c;餐饮等众多营销功能&#xff0c;商城系统版本号为2.6.7.1&a…

Go语言高级面试必考:切片(slice)你真的掌握了吗?

目录 1. 切片是个啥?从数组到切片的灵魂进化 数组与切片的爱恨情仇 切片的内存结构:三巨头共舞 切片的初始化方式:灵活到飞起 切片的“引用”特性:福也是祸 源码初探:切片的诞生 2. 切片三剑客:len、cap 和底层数组的三角恋 len 和 cap 的微妙关系 切片共享的秘密…

monorepo + Turborepo --- 开发应用程序

目录 配置开发任务 在 dev 之前运行设置任务 运行特定应用程序 使用终端 UI 与任务交互 监听模式 watch 将 turbo watch 与持久任务一起使用 依赖感知的持久任务 没有依赖感知的持久任务 缓存 任务输出 局限性 在 Monorepo 中开发应用程序可以解锁强大的工作流程&…

C#字符串相关库函数运用梳理总结 + 正则表达式详解

C# 字符串常用库函数总结 &#x1f539; 1. 字符串比较 方法说明示例string.Equals()比较两个字符串是否相等&#xff08;可忽略大小写&#xff09;string.Equals("abc", "ABC", StringComparison.OrdinalIgnoreCase) / !判断两个字符串是否相等/不等&quo…

投机采样(Speculative Decoding)

投机采样&#xff08;Speculative Decoding&#xff09; 是一种加速大型语言模型&#xff08;LLM&#xff09;推理的技术&#xff0c;其核心思想是通过预生成候选token序列并异步校验&#xff0c;从而减少主模型的计算量&#xff0c;同时保持生成结果的准确性。 核心思想是通过…

如何将华为手机中的照片传输到电脑

华为手机在众多手机品牌中以其出色的品质脱颖而出&#xff0c;尤其是其摄像头功能。有时&#xff0c;你可能在华为手机上积累了太多有意义的照片&#xff0c;想要将这些照片上传到电脑以释放手机存储空间。然而&#xff0c;出于用户信息安全的考虑&#xff0c;一些便捷的方法可…

whitt算法之特征向量的尺度

whitt中特征值不相等判别条件另一个条件的意思&#xff0c; 实际上这两个条件都没用&#xff0c;不用看&#xff0c;特征值排序&#xff0c;如果现在顺序对λ1/λ1‘ w λ2/λ2 -w 此时取相位就是0&#xff0c;最小了 如果相反就是面的是0我的代码用最优相位内积去交换位置公…

【Note】《深入理解Linux内核》 第十九章:深入理解 Linux 进程通信机制

《深入理解Linux内核》 第十九章&#xff1a;深入理解 Linux 进程通信机制&#xff08;Process Communication&#xff09;关键词&#xff1a;IPC、信号、管道、FIFO、消息队列、信号量、共享内存、套接字、内核对象、同步机制一、进程通信概述 1.1 为什么需要进程通信 在 Linu…

【Mac 从 0 到 1 保姆级配置教程 19】- 英语学习篇-我的英语工作流分享(AI 辅助学习)

文章目录前言听力沉浸式翻译阅读Easydict配置自定义字典&#xff08;重点&#xff09;欧陆词典沙拉查词沉浸式翻译写作Eearthworm英文提问口语最后学习资料系列教程前言 本文介绍一下我日常如何学习和使用英语的工作流&#xff0c;包括一些常用好用的工具&#xff0c;好的工具…

从库函数到API接口,深挖不同语言背后的“封装”与“调用”思想

个人主页-爱因斯晨 优秀文章推荐 文章目录个人主页-爱因斯晨优秀文章推荐引言一、三种调用机制概述C语言的库函数Python 的导包机制Java 的 API 接口调用综上&#xff1a;二、它们的相同点&#xff1a;封装与调用三、不同之处**对比核心维度****细节串讲**1. **C 语言&#xf…

基于NCNN框架在Android平台实现YOLOv8目标检测模型的高效部署与实践

随着移动设备计算能力的提升&#xff0c;越来越多的深度学习模型被部署到移动端&#xff0c;以实现实时、低延迟的应用场景。YOLO系列的在目标检测任务中表现出色&#xff0c;具有精度高、速度快的优势。本文将详细介绍如何基于NCNN框架 &#xff0c;在Android平台 上高效部署Y…

华为动态路由配置

问题描述&#xff1a;针对四个路由器在不同的网段场景中&#xff0c;对四个路由器进行动态路由配置。下面以如下场景为例&#xff0c;介绍详细配置过程。配置过程&#xff1a; 1、每个路由器的接口配置IP地址 路由器AR1中每个接口配置IP地址。 sys # 进入系统视图 interface g…

分布式事务解决方案(三)

在Java分布式系统领域&#xff0c;传统强一致性方案&#xff08;如2PC、3PC&#xff09;在高并发、复杂业务场景下暴露出性能瓶颈和阻塞问题。而Saga模式与事件溯源&#xff08;Event Sourcing&#xff09;作为更具弹性和扩展性的解决方案&#xff0c;逐渐成为分布式事务处理和…

【时时三省】(C语言基础)通过指针引用数组

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省数组元素的指针一个变量有地址&#xff0c;一个数组包含若干元素&#xff0c;每个数组元素都在内存中占用存储单元&#xff0c;它们都有相应的地址。指针变量既然可以指向变量&#xff0c;当然…

【WEB】Polar靶场 21-25题 详细笔记

二十一.php very nicephp又是你 ,但是经过这么多次折磨后我感觉我已经有一点抗性了老规矩&#xff0c;先看知识点PHP 序列化是将 PHP 变量&#xff08;如对象、数组&#xff09;转换为字符串的过程&#xff0c;便于存储或传输。反序列化则是将字符串还原为原始变量。这在缓存、…

【Guava】1.0.设计虚拟机的方向

【Guava】1.0.设计虚拟机的方向虚拟机是什么&#xff1f;栈式虚拟机栈式虚拟机的优缺点题外话虚拟机是什么&#xff1f; 虚拟机&#xff08;VirtualMachine, VM&#xff09;是一种计算机程序或系统&#xff0c;它通过软件模拟物理计算机的硬件运行环境&#xff0c;使得多个操作…

[附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+jsp实现的高校实验室资源综合管理系统,推荐!

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本高校实验室资源综合管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大…