Vue3+TS项目---实用的复杂类型定义总结
namespace
概念
在TypeScript中,namespace是一种用于组织代码得结构,主要用于将相关得功能(例如类、接口、函数等)组合在一起。它可以帮助避免命名冲突,尤其是在大项目中。
用法
1.定义命名空间
使用namespace关键字定义一个命名空间,并在其中包含类、接口、函数等等。以下举例是我在项目中定义得接口参数类型,因为我得接口参数类型是放在一个文件中进行维护得,所以难免会出现相同参数名不同类型得情况出现。所以这里可以使用namaspace来定义不同模块下得接口参数类型。
declare namespace Api {namespace Auth {type systemInfo = {logo: string;systemName: string;nickname: string;avatar: string;email: string;tenantId: string;}type Domain = {domainName: string;}}
}
2.访问命名空间中的成员
需要使用命名空间名来访问其成员,使用.操作符。
/*** 获取系统名称,logo等信息* @param domainName*/
export function fetchPostSystemInfo(params?: Api.Auth.Domain){return request<Api.Auth.systemInfo>({url: 'xxxxx',method: 'get',params})
}
以上举例限制fetchPostSystemInfo异步请求中传去的参数params的类型约束是Api.Auth.Domain,
调用时通过request<Api.Auth.systemInfo>
明确指定响应数据类型是Api.Auth.systemInfo,确保调用者可以在代码中获得类型提示和安全的类型检查。
3.使用
const systemInfo:Api.Auth.systemInfo = reactive({logo: '',systemName: '',nickname: '',avatar: '',email: '',
})async function getSystemInfo() {const { data, error } = await fetchPostSystemInfo({ domainName: window.location.hostname });if (!error && data) {Object.assign(systemInfo, data);}
}
类型定义扩展
泛型类型
实例1
declare namespace Api {namespace Auth {type emailToken<T = any> = {email: string;} & T;}
}
这段代码定义了一个泛型类型emailToken,它由一个对象组成,包含一个名为email的字符串属性,并且可以通过泛型参数T扩展。T默认是any类型。
具体含义是:
- emailToken<T = any >:这是一个泛型类型定义,其中T是一个可选的泛型参数,默认值是any。如果你在使用时不传入T,则T的类型会是any。
- { email : string } & T:这表示emailToken 类型是由两个部分组成的对象类型:
-
- 一个固定的属性email,类型是string
- 通过& T,可以扩展其他属性,这些属性来源T。也就是说,emailToken是一个包含email属性的对象,并且可以包含任何你传入的T类型的属性
举例如下:
type CustomToken = emailToken<{token: string }>;
// CustomToken 类型为 { email: string, token: string }
在上面的例子中,CustomToken类型包含两个属性:email和token,其中email是固定的,而token是通过传入T定义的。
使用:
/*** 获取验证码* @param email* return string*/
export function fetchGetEmailToken(params?: Api.Auth.emailToken) {return request<string>({url: '/usercenter/api/uc/otp/request/email',method: 'post',)}
}let emailToken: string = '';
async function getEmailToken(email: string) {const { data: token, error } = await fetchGetEmailToken({ email });if (!error && token) {emailToken = token || '';window.$message?.success?.('验证码发送成功')return emailToken;}
}
实例2
type Response<T = unKnown> = {statusCode: number;message: string;success: boolean;timestamp: string;result: T
}
- 泛型T:
-
- Response是一个泛型类型,接受一个类型参数T,默认值为unknowm。
- T可以是任何类型,允许Response在使用时具有灵活性
- 属性
-
- statusCode: string; :表示后端服务的请求状态码,例如 401,200
message: string;
:表示后端服务的响应消息,提供对状态的更详细说明。- result: T; :表示响应的具体数据,类型为T。这允许Response用于多种数据结构
示例1 返回简单数据
const simpleResponse:Response<string> = {statusCode: 200,message: "request is success",timestamp: "1729159210638",success: true,result: "Some string data"
}
在这个例子中,result是一个字符串
示例2 返回对象数据
type User = {id:number;name:string;
}
const userResponse:Response<User> = {statusCode: 200,message: "request is success",timestamp: "1729159210638",success: true,result: {id: 1,name: 'Hzz'}
}
在这个例子中,data是一个User类型的对象
示例3 返回数组数据
cosnt usersResponse: Response<User []> = {statusCode: 200,message: "request is success",timestamp: "1729159210638",success: true,result:[{ id: 1, name: "Alice" },{ id: 2, name: "Bob" }]
}
这里,data是一个User对象的数组
扩展用法
可以通过不同的方式扩展Response类型,以适应更复杂的需求。
添加分页功能
假设你希望响应支持分页,可以扩展Response来包括分页信息:
type PaginatedResponse<T> = {items: T[];total: number;
}type Response<T = unknowm> = {statusCode: number;message: string;success: boolean;timestamp: string;result: PaginatedResponse<T>; // 包含分页信息
}
type User = {id:number;name:string;
}
// 使用示例
const paginatedUserResponse:Response<User> = {statusCode: 200,message: "request is success",timestamp: "1729159210638",success: true,result:{items:[{id: 1, name: "Alice"},{id: 1, name: "Alice"}],total: 2}
}
结合错误信息
如果你希望在失败的情况下包含错误信息,可以扩展响应结构:
type ErrorResponse = {errorCode: string;errorDetails?: string;
}type Response<T = unknown> = {statusCode: number;message: string;success: boolean;timestamp: string;result?: T; // result是可选的error?: ErrorResponse;
}const errorResponse: Response = {statusCode: 200,message: "request is success",timestamp: "1729159210638",success: true,error:{errorCode: '404',errorDetails: "The user with the specified ID does not exist.",}
}
总结:
- Response是一个灵活的泛型类型,用于描述后端服务的响应,包括状态、消息和具体数据
- 通过将T用于result属性,可以轻松适应不同的数据结构
映射类型
declare module "@elegant-router/types" {export type RouteLayout = "base" | "blank" | "baseVariant";/*** route map*/export type RouteMap = {"root": "root";"403": "/403";"404": "/404";"500": "/500";"application": "/application";"application_develop": "/application/develop";"client": "/client";};/*** route key*/export type RouteKey = keyof RouteMap;/*** route path*/export type RoutePath = RouteMap[RouteKey];/*** custom route key*/ export type CustomRouteKey = Extract<RouteKey,| "root"| "not-found"| "exception"| "exception_403"| "exception_404">;
}
以上定义类型主要用来描述路由映射和键、值得类型,详细解析如下:
RouteMap
类型 是一个对象,它描述了路由得命名和对应关系
RouteKey
类型
- keyof 操作符用于获取某个类型得键的集合
- 在这里,keyof RouteMap将会提取RouteMap中所有的键,形成一个联合类型,也 就是
"403" | "404 | "500" | "application" | "application_develop" | "client"
。
因此,RouteKey
类型将会是:
type RouteKey = "403" | "404" | "500" | "application" | "application_develop" | "client";
在实际开发中常用于确保路由键与路由路径的映射是安全的和类型化的。例如,使用RouteKey
来引用某个路由时,TypeScript会确保你只能使用定义过的路由键,避免拼写错误等问题。
RoutePath
类型
在TypeScript中,使用方括号[]可以通过索引访问对象类型的值,语法如下:
T[K]
- T是一个对象类型
- K是T的键(可以是单个键或者键的联合类型)
通过T[k]这种索引访问方式,可以获取T中键K对应的值的类型。如果K是联合类型,结果会是所有键对应值的联合类型。
因此,在 exporttypeRoutePath = RouteMap[RouteKey]; 中
RouteMap
是一个对象类型 ,它的键是RouteKey,即 "403" | "404" | "500" | "application" | "application_develop" | "client" ,对应的值的路径字符串是对象的值,RouteMap[RouteKey]
会返回 RouteMap 中键的值的类型
RouteMap["root"] // "/"
RouteMap["403"] // "/403
...
最终结果:
type RoutePath = "/" | "/403" | "/404" | "/500" | "/application" | "/application/develop" | "/client";
总结:这种用法可以在需要动态获取某些键对应值的场景中确保类型安全,比如在路由系统中确保路径类型和路由键的一致性。
Exclude
类型工具
Exclude<T, U>是TypeScript内置的条件类型,它用于从类型T中排除那些可以分配给类型U的成员。它的定义是:
type Exclude<T, U> = T extends U ? never : T;
- 如果T中某个类型能够分配给U(T extends U 为 true),那么返回never类型(表示排除该成员)
- 否则,返回T本身
分析以下类型结果:
const RouteKey = "403" | "root" | "not-found" | "application" | "application_develop" | "client"; | "/client";
type I18nRouteKey = Exclude<RouteKey, 'root' | 'not-found'>;const RouteKey1 = 'root' | 'not-found'
type I18nRouteKey1 = Exclude<RouteKey1, 'root' | 'not-found'>;
I18nRouteKey:
- 从
RouteKey
中排除 'root' | 'not-found' 这两个键 - 那么 I18nRouteKey的最终结果是:type I18nRouteKey = "403" | "application" | "application_develop" | "client"; | "/client";
I18nRouteKey1:
- 从
RouteKey1
中排除 'root' | 'not-found' 这两个键 - 那么 I18nRouteKey1的最终结果是 type I18nRouteKey1 = never
结论:
I18nRouteKey1 的结果是never,是因为 因为 RouteKey1
中只有 "root"
和 "not-found"
。
当 RouteKey 中有其他键时, I18nRouteKey 会成为这些剩余键的联合类型。
Omit
工具类型
Omit<T, K>
是 TypeScript的内置工具类型,用于从类型T中排除指定的键K。
- T:要修改的原始类型
- K:要排除的键,可以是单个键或者多个键的联合类型
举例说明:
定义Breadcrumb结构
interface Menu {key: string;// 唯一标识符,用于识别菜单项label: string;// 显示给用户的菜单项标签i18nKey?: I18n.I18nKey | null;// 可选的国际化键,用于多语言支持routeKey: RouteKey;// 路由的键,表示该菜单项对应的路由routePath: RoutePath;// 路由的路径,指向该菜单项的具体路径icon?: () => VNode;// 可选的图标,返回一个虚拟节点(通常用于渲染图标)children?: Menu[];// 可选的子菜单项,数组类型,表示该菜单项下的子菜单
}type Breadcrumb = Omit<Menu, 'children'> & {options?: Breadcrumb[];
}
解释:
Omit<Menu, 'children'>
: 使用Omit工具类型从Menu接口中排除children属性。这样,Breadcrumb不会直接包含children。- & { options?: Breadcrumb[]; }:通过交叉类型将Omit的结果与一个新对象类型结合,这个新类型包含一个可选的属性options,其类型为Breadcrumb[],表示该面包屑导航项包含其他Breadcrumb对象的数组
Breadcrumb
的最终结构
type Breadcrumb = {key: string;// 继承自 Menulabel: string;// 继承自 Menui18nKey?: I18n.I18nKey | null;// 继承自 MenurouteKey: RouteKey;// 继承自 MenuroutePath: RoutePath;// 继承自 Menuicon?: () => VNode;// 继承自 Menuoptions?: Breadcrumb[]; // Breadcrumb[];
}
用法示例
假设我们要构建一个面包屑导航,可以使用Breadcrumb类型如下:
const breadcrumn:Breadcrumb = {key: "home",label: "Home",routeKey: "root",routePath: "/",icon: () => <span>🏠</span>, //可选的图标,返回一个虚拟节点options:[{key: "about",label: "About us",routeKey: "about",routePath: "/about"icon: () => <span>ℹ️</span>, // 子面包屑的图标options: [//....]},{key: "contact",label: "Contact",routeKey: "contact",routePath: "/contact",icon: () => <span>📞</span>, // 子面包屑的图标}]
}
说明
key
、label
、routeKey
和routePath
属性是必需的,定义了面包屑项的基本信息。icon
属性是一个可选的函数,返回一个虚拟节点(这里使用了简单的 Emoji 作为示例图标)。options
属性用于定义子面包屑项,支持嵌套结构。
相关文章:
Vue3+TS项目---实用的复杂类型定义总结
namespace 概念 在TypeScript中,namespace是一种用于组织代码得结构,主要用于将相关得功能(例如类、接口、函数等)组合在一起。它可以帮助避免命名冲突,尤其是在大项目中。 用法 1.定义命名空间 使用namespace关键…...
尚硅谷rabbitmq2024 工作模式路由篇 第11节 答疑
String exchangeName "test_direct"; /! 创建交换机 人图全 channel.exchangeDeclare(exchangeName,BuiltinExchangeType.DIREcT, b: true, b1: false, b2: false, map: null); /1 创建队列 String queue1Name "test_direct_queue1"; String queue2Name &q…...

HTTP vs WebSocket
本文将对比介绍HTTP 和 WebSocket ! 相关文章: 1.HTTP 详解 2.WebSocket 详解 一、HTTP:请求/响应的主流协议 HTTP(超文本传输协议)是用于发送和接收网页数据的标准协议。它最早于1991年由Tim Berners-Lee提出来&…...

R语言医学数据分析实践-数据读写
【图书推荐】《R语言医学数据分析实践》-CSDN博客 《R语言医学数据分析实践 李丹 宋立桓 蔡伟祺 清华大学出版社9787302673484》【摘要 书评 试读】- 京东图书 (jd.com) R语言编程_夏天又到了的博客-CSDN博客 R编程环境的搭建-CSDN博客 在分析公共卫生数据时,数…...
JavaWeb环境下Spring Boot在线考试系统的优化策略
摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了基于JavaWeb技术的在线考试系统设计与实现的开发全过程。通过分析基于Java Web技术的在线考试系统设计与实现管理的不足,创建了一个计算机管理基于Ja…...

ETL技术在金蝶云星空与旺店通WMS集成中的应用
金蝶云星空数据集成到旺店通WMS的技术案例分享 在数字化转型的背景下,现代企业对系统间的数据集成需求日益增加。本篇文章将以“组装入库>其他入库单-1”方案为例,详细解析如何通过轻易云数据集成平台,实现金蝶云星空与旺店通WMS之间的数…...
【力扣热题100】3194. 最小元素和最大元素的最小平均值【Java】
题目:3194.最小元素和最大元素的最小平均值 你有一个初始为空的浮点数数组 averages。另给你一个包含 n 个整数的数组 nums,其中 n 为偶数。 你需要重复以下步骤 n / 2 次: 从 nums 中移除 最小 的元素 minElement 和 最大 的元素 maxElement…...

机器学习拟合过程
import numpy as np import matplotlib.pyplot as plt# 步骤1: 生成模拟数据 np.random.seed(0) X 2 * np.random.rand(100, 1) y 4 3 * X 2 * X**2 np.random.randn(100, 1)# 步骤2: 定义线性模型 (我们从随机权重开始) w np.random.randn(2, 1) b np.random.randn(1)#…...

如何快速部署一套智能化openGauss测试环境
一、openGauss介绍 openGauss是一款开源关系型数据库管理系统,采用木兰宽松许可证v2发行,允许用户自由地复制、使用、修改和分发软件。openGauss内核深度融合了华为在数据库领域多年的研发经验,结合企业级场景需求,持续构建竞争力…...
【设计模式】深入理解Python中的原型设计模式
深入理解Python中的原型设计模式 在软件开发中,有时需要创建对象的过程非常复杂或者代价较高,而在同一类对象的实例之间有很多重复的属性。为了避免重复构造对象,提升性能和效率,原型设计模式(Prototype Pattern&…...
Django CORS配置方案
参考 https://pypi.org/project/django-cors-headers/ 在setting.py中设置 INSTALLED_APPS [......corsheaders, #添加此行 ]MIDDLEWARE[......corsheaders.middleware.CorsMiddleware, #添加此行django.middleware.common.CommonMiddleware,#django.middleware.csrf.CsrfVi…...

2024年开放式耳机哪个牌子好?推荐最好的顶级开放式耳机品牌
在当下,开放式耳机逐渐成为众多消费者的新宠。与传统入耳式耳机相比,开放式耳机展现出诸多独特之处。它可以呈现出更清晰的音质效果,让用户有更美妙的听觉体验。在佩戴感上,开放式耳机更为舒适,不会给耳朵带来压迫感。…...

零基础读懂Stable Diffusion!
前言 一文搞懂Stable Diffusion是什么,怎么训练和使用,语义信息影响生成图片的过程。>>[][加入极市CV技术交流群,走在计算机视觉的最前沿] 前几个月AIGC可谓是大热了一把,各种高质量的生成图片层出不穷,而其中…...
Hash Join 和 Index Join工作原理和性能差异
在数据库查询中,Hash Join 和 Index Join 是两种常见的表连接策略。了解它们的工作原理和性能差异有助于设计高效的数据库查询。我们可以使用 Java 模拟这两种不同的连接方式,并进行性能对比。 1. Hash Join 和 Index Join 的概念: Hash Joi…...
Apifox简介及使用
Apifox 是一款集 API文档管理、接口调试、接口自动化测试 和 Mock 功能于一体的全功能工具,旨在为开发者和测试人员提供一个高效的一站式解决方案。它融合了 Postman、Swagger、JMeter 等工具的优势,能够极大地提升团队协作和 API 开发的效率。 在实际开…...
十、IPD 实施细节(产品设计与开发管理)
产品设计与开发管理 产品设计与开发管理是IPD(集成产品开发)实施过程中的核心环节。它确保从概念设计到最终产品的实现能够按照预定的质量、成本、进度目标顺利完成,并与市场需求、技术发展及企业战略保持一致。IPD强调产品设计与开发管理过程中跨职能团队的协作、流程的系…...

MySQL-13.DQL-聚合函数
一.DQL-分组查询 二.聚合函数 -- DQL:分组查询 -- 聚合函数 -- 1.统计该企业员工数量 count select count(id) from tb_emp; select count(job) from tb_emp;select count(A) from tb_emp; select count(*) from tb_emp;-- 2.统计该企业最早入职的员工 min select min(entr…...
为什么跟别人学习如何证明定理要远比使用定理更有意义
目录 背景 为什么跟别人学习 什么是高人,如何判断 高人定义 如何判断一个人的能力? 如何考量一个人的成就? 只知道使用定理的局限性 1. 缺乏灵活性和适应性 2. 无法创新或拓展新方法 3. 容易误用或误解定理 4. 难以推理和分析复杂问…...
Qt在Win,Mac和Linux的开机自启设置
Windows Windows 使用注册表来管理开机自启的应用程序。 void runWithSystem(const QString& name, const QString& path, bool autoRun) {QSetting reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSetting::NativeForma…...

spring boot热部署
使用热部署解决了每次都需要重新启动的问题,但不过热部署的在对于改动比较小时速度可能快一些,改动大的话尽量停止 1.使用热部署之前需要在pom.xml文件中导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifa…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...