Vue3+TS项目---实用的复杂类型定义总结

news2024/10/21 12:03:06

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;// 继承自 Menu
  label: string;// 继承自 Menu
  i18nKey?: I18n.I18nKey | null;// 继承自 Menu
  routeKey: RouteKey;// 继承自 Menu
  routePath: RoutePath;// 继承自 Menu
  icon?: () => VNode;// 继承自 Menu
  options?: 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>, // 子面包屑的图标
      }
    ]
}

说明

  • keylabelrouteKeyroutePath 属性是必需的,定义了面包屑项的基本信息。
  • icon 属性是一个可选的函数,返回一个虚拟节点(这里使用了简单的 Emoji 作为示例图标)。
  • options 属性用于定义子面包屑项,支持嵌套结构。

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

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

相关文章

【C++】哈希表的模拟实现

目录 一、闭散列&#xff08;开放定址定法&#xff09; 1、哈希表的结构&#xff1a; 2、哈希表的插入&#xff1a; 3、哈希表的查找&#xff1a; 4、哈希表的删除&#xff1a; 二、开散列&#xff08;哈希桶&#xff09; 1、哈希表的结构&#xff1a; 2、构造与析构&a…

若依前后分离版集成积木报表进行token传递

若依分离板集成积木报表就不说了需要的请移步&#xff1a;若依前后分离版集成积木报表-CSDN博客 考虑到前端摸鱼不干活,所以一般都是前后端都干&#xff0c;我这里前后端都搞上&#xff0c;你们直接抄&#xff0c;抄完接着去摸鱼&#xff0c;代码不美观&#xff0c;轻喷 一、…

【JavaEE】【多线程】synchronized和死锁

目录 一、synchronized详解1.1 互斥1.2 可重入 二、死锁2.1 死锁成因2.2 避免死锁 一、synchronized详解 1.1 互斥 synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到 同一个对象 synchronized 就会阻塞等待. 语法&#xff1…

AI时代程序员何去何从?提升自我还是被淘汰出局!

AI 在编程界的使用变得越来越普遍了。随着 ChatGPT 的横空出世&#xff0c;各种大语言模型如雨后春笋不断出现。国外如谷歌 Bard、Anthropic 的 Claude&#xff0c;国内如百度文心一言、阿里通义千问、讯飞星火认知大模型、昆仑万维天工大模型等。 想想看&#xff0c;以前得花好…

支持国密算法的数字证书-国密SSL证书详解

在互联网中&#xff0c;数字证书作为标志通讯各方身份信息的数字认证而存在&#xff0c;常见的数字证书大都采用国际算法&#xff0c;比如RSA算法、ECC算法、SHA2算法等。随着我国加强网络安全技术自主可控的大趋势&#xff0c;也出现了支持国密算法的数字证书-国密SSL证书。那…

【网络安全】缓存欺骗问题之查看个人资料接口

未经许可,不得转载。 文章目录 正文正文 目标网站 target.com,查看个人资料页面时,API 端点为/get_user,完整的 URL 是 https://target.com/web-api/v1/get_user?timestamp=123456(其中 timestamp 是一个易受攻击的参数)。 我注意到响应中有一个 cf-cache-status= MISS…

k8s部署Kafka集群超详细讲解

准备部署环境 Kubernetes集群信息 NAMEVERSIONk8s-masterv1.29.2k8s-node01v1.29.2k8s-node02v1.29.2 Kafka&#xff1a;3.7.1版本&#xff0c;apche版本 Zookeeper&#xff1a;3.6.3版本 准备StorageClass # kubectl get sc NAME PROVISIONER RECLA…

Docker安装ActiveMQ镜像以及通过Java生产消费activemq示例

拉取镜像 docker pull docker.io/webcenter/activemq 启动容器 docker run -d --name myactivemq -p 61616:61616 -p 8162:8161 docker.io/webcenter/activemq:latest 这样就代表启动成功了 浏览器访问 http://localhost:8162/ admin admin 开启验证 修改配置文件/opt/ac…

关于k8s集群高可用性的探究

1. k8s的高可用的核心是什么&#xff1f; 说到核心、本质 意味着要从物理层来考虑技术 k8s是一个容器编排管理工具&#xff0c;k8s受欢迎的时机 是docker容器受欢迎时&#xff0c;因为太多的docker容器&#xff0c;管理起来是一个大工程 那么刚好k8s是google自己用了十来年…

STM32L031F6P6基于CubeMX的串口通信调试笔记

用CubeMX创建项目 本实例用的PA14、PA13两个引脚&#xff0c;LPUART1。 对串口参数进行设置&#xff1a; 开启串口中断&#xff1a; 时钟源设置成内部高频时钟&#xff1a; 对项目进行设置&#xff1a; 生成代码&#xff1a; 在串口初始化函数中加入 __HAL_UART_ENA…

Asp.net Core MVC 动态路由

动态路由 asp.net core 3.0 就支持了 // 映射关系public class TranslationDatabase{private static Dictionary<string, Dictionary<string, string>> Translations new Dictionary<string, Dictionary<string, string>>{{"en", new Dictio…

《Vue3 踩坑》expose 和 defineExpose 暴露属性或方法注意事项

选项式写法 使用 选项式API - 状态选项 - expose 一定要注意&#xff1a; 接下来&#xff0c;进一步看示例说明&#xff1a; 设置 expose 仅显示列出的属性/方法才能被父组件调用&#xff1b;代码第 2 行&#xff0c;父组件可访问属性 a 和 方法 myFunc01&#xff0c;不可访…

Windows server 2022 数据中心版本的安装

安装前的准备工作&#xff1a; 1.准备好VMware虚拟机&#xff08;略&#xff09; 2.准备好镜像 图1-1 准备安装镜像 3.准备好安装的位置&#xff08;F盘2022vm文件夹&#xff09; 图1-2 选择并设定安装位置 4.开始安装 图1-3 开心VMware安装向导 图1-4 插入光盘镜像 图1-5…

视频转文字工具搜集

视频转文字工具是一种能够将视频中的音频内容转化为文字的软件或在线服务。这类工具通常支持多种视频格式和语言&#xff0c;适用于不同的场景和需求。以下是一些推荐的视频转文字工具及其特点&#xff1a; 媒关系&#xff1a;这是一款免费的视频转文字工具&#xff0c;支持多种…

ABAQUS应用11——支座弹簧

文章目录 0、背景1、ABAQUS中几类弹簧的简介2、SPRING1的性质初探 0、背景 1、ABAQUS中几类弹簧的简介 先说参考来源&#xff0c;ABAQUS2016的帮助文档里第4卷&#xff0c;32.1.1节&#xff0c;有三种弹簧&#xff08;SPRING1 、SPRING2 以及SPRINGA&#xff09;。 三种弹簧里…

【AIGC】ChatGPT提示词Prompt高效编写模式:Self-ask Prompt、ReACT与Reflexion

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;自我提问 (Self-ask Prompt)如何工作应用实例优势结论 &#x1f4af;协同思考和动作 (ReACT)如何工作应用实例优势结论 &#x1f4af;失败后自我反思 (Reflexion)如何工作…

oracle数据恢复—文件损坏导致Oracle数据库打开报错的数据恢复案例

oracle数据库故障&分析&#xff1a; 打开oracle数据库时报错&#xff0c;报错信息&#xff1a;“system01.dbf需要更多的恢复来保持一致性&#xff0c;数据库无法打开”。急需恢复zxfg用户下的数据。 出现上述报错的原因有&#xff1a;控制文件损坏、数据文件损坏、数据文件…

FastDFS单节点部署

FastDFS单节点部署 1、FastDFS入门1.1 分布式文件系统1.2 FastDFS 简介1.3 FastDFS 发展历史1.4 FastDFS 整体架构1.5 FastDFS 线上使用者 2、FastDFS 环境搭建2.1 FastDFS 安装2.1.1 安装前的准备2.1.2 安装 libfastcommon库2.1.3 安装 FastDFS 2.2FastDFS 配置2.2.1 去掉/etc…

python爬虫快速入门之---Scrapy 从入门到包吃包住

python爬虫快速入门之—Scrapy 从入门到包吃包住 文章目录 python爬虫快速入门之---Scrapy 从入门到包吃包住一、scrapy简介1.1、scrapy是什么?1.2、Scrapy 的特点1.3、Scrapy 的主要组件1.4、Scrapy 工作流程1.5、scrapy的安装 二、scrapy项目快速入门2.1、scrapy项目快速创建…

Spring Boot框架下JavaWeb在线考试系统的创新实现

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…