深入浅出 TypeScript 泛型:类型安全的艺术与实践
文章目录
- 一、泛型的核心概念
- 1.1 类型参数:代码中的类型变量
- 1.2 类型推断:让代码保持简洁
- 二、泛型的四大应用场景
- 2.1 泛型函数:打造通用工具库
- 2.2 泛型接口:定义灵活的数据结构
- 2.3 泛型类:构建类型安全的容器
- 2.4 泛型类型别名:创建高级类型工具
- 三、高级泛型技巧
- 3.1 泛型约束:给类型参数带上镣铐
- 3.2 默认类型参数:提供优雅的备选方案
- 3.3 类型推断与条件类型
- 四、泛型使用黄金法则
- 五、从理论到实践:一个真实案例
- 六、总结
为什么需要泛型?
在 JavaScript 中,我们常常需要编写处理多种数据类型的通用函数。比如一个获取数组首元素的函数 getFirst(arr),它应该对数字数组返回数字,对字符串数组返回字符串。但在原生 JS 中,我们无法在类型层面表达这种关系。
TypeScript 的泛型正是为解决这类问题而生。 泛型就像给类型系统插上翅膀,让我们在保持类型安全的同时,编写高度灵活的通用代码 。它通过将类型参数化,建立了输入类型与输出类型之间的精确映射关系。
一、泛型的核心概念
1.1 类型参数:代码中的类型变量
泛型的核心在于类型参数(Type Parameter), 用尖括号<T>声明:
/*** 泛型标识函数:返回与输入类型完全相同的值* @param arg - 泛型参数 T 的动态类型输入* @returns 保持类型一致性的返回值*/
function identity<T>(arg: T): T {return arg
}
T 是一个类型变量,调用时动态确定。输入 number 类型,返回 number 类型,输入string类型,返回string类型
1.2 类型推断:让代码保持简洁
TypeScript 能自动推断类型参数,多数情况下无需显式指定:
// 类型推断自动识别数字类型
const num = identity(42) // T 推断为 number// 类型推断自动识别字符串类型
const str = identity('TypeScript') // T 推断为 string
二、泛型的四大应用场景
2.1 泛型函数:打造通用工具库
/*** 安全的数组拼接函数* @param arr1 - 第一个同类型数组* @param arr2 - 第二个同类型数组* @returns 合并后的新数组,保持元素类型一致*/
function concat<T>(arr1: T[], arr2: T[]): T[] {return [...arr1,...arr2]
}concat([1,2], [3]) // ✅ 正确:T 为 number
concat(['a', 'b'], [3]) // ❌ 错误:类型不统一
实战技巧:当需要处理多种数据类型但保持内部一致性或局部一致性时,泛型函数是最佳选择。
2.2 泛型接口:定义灵活的数据结构
/*** 通用 API 响应接口* @template T - 响应数据的动态类型*/
interface ApiResponse<T> {data: T; // 核心数据内容code: number; // 状态码message?: string; // 可选描述信息
}
// 用户数据接口的泛型应用
const userResponse: ApiResponse<User> = { ... }
// 商品数据接口的泛型应用
const productResponse: ApiResponse<Product> = { ... }
设计哲学 :通过泛型接口,我们可以创建出像乐高积木一样可复用的类型定义。
2.3 泛型类:构建类型安全的容器
/*** 泛型栈数据结构实现* @template T - 栈元素的动态类型*/
class Stack<T> {private items: T[] = [] // 内部存储数组// 压入元素(类型必须匹配)push(item: T) {this.items.push(item)}// 弹出元素(保持类型一致性)pop(): T | undefined {return this.items.pop()}
}
const numberStack = new Stack<number>()
numberStack.push(42) // ✅ 正确
numberStack.push('42') // ❌ 类型错误
最佳实践 :集合类(如 List、Queue)是泛型类的典型应用场景,确保容器内元素类型一致。
2.4 泛型类型别名:创建高级类型工具
// 定义可为空的泛型类型
type Nullable<T> = T | null | undefined/*** 字典类型定义* @template K - 键的类型(需继承 string)* @template V - 值的类型*/
type Dictionarty<K extends string, V> = Record<K, V>// 用户字典的具体应用
type UserMap = Dictionarty<string, User>
威力展现:通过组合泛型与条件类型,可以创建出强大的类型工具(如 Partial, Required)。
三、高级泛型技巧
3.1 泛型约束:给类型参数带上镣铐
// 定义必须包含 length 属性的约束接口
interface HasLength {length: number
}/*** 带约束的泛型函数* @template T - 必须实现 HasLength 接口的类型* @param obj - 包含 length 属性的对象*/function logLength<T extends HasLength>(obj: T) {console.log(obj.length) // 安全访问 length 属性
}logLength("abc"); // ✅ 字符串有 length 属性
logLength({}); // ❌ 空对象缺少 length 属性
设计模式:通过 extends 约束,确保类型参数具备必要特性,类似接口的契约式设计。
3.2 默认类型参数:提供优雅的备选方案
/*** 分页数据结构接口* @template T - 列表项类型(默认为 string)*/interface Pagination<T = string> {items: T[] // 数据列表page: number // 当前页码
}
const stringPage = new Pagination(); // ✅ T 默认为 string
const numberPage = new Pagination<number>(); // 显式指定类型
使用场景: 当大部分用例使用同一类型时,默认参数能显著简化代码。
3.3 类型推断与条件类型
/*** 解包数据类型工具* @template T - 输入类型* @returns 如果是数组则返回元素类型,否则饭会员类型*/type Unbox<T> = T extends Array<infer U> ? U : Ttype Nested = Unbox<string[]> // ✅ 推断为 string
type simple = Unbox<number> // ✅ 保持为 number
黑魔法:infer 关键字允许我们在条件类型中进行类型推导,是实现复杂类型逻辑的关键。
四、泛型使用黄金法则
- 克制原则
- 当类型参数仅出现一次时,可能不需要泛型
- 优先使用 TypeScript 内置工具类型
- 简单至上
// ❌ 错误示范:过度设计的复杂泛型
function bad<T, U extends (arg: T) => boolean>(arr: T[], fn: U) { ... }// ✅ 优化版本:简化类型参数
function good<T>(arr: T[], fn: (arg: T) => boolean) { ... }
- 语义化命名
- 使用
T,K,U作为基础类型参数 - 特定场景使用有意义的名称:
Tkey,TValue
- 避免类型体操
- 复杂的泛型逻辑会显著降低代码可读性
- 必要时添加详细注释说明类型逻辑
五、从理论到实践:一个真实案例
假设我们需要实现一个安全的 API 请求层:
/*** 通用 API 相应接口* @template T - 相应数据的动态类型*/
interface ApiResponse<T> {success: boolean // 请求状态data: T // 核心数据内容error?: string // 可选错误信息
}/*** 通用数据请求函数* @template T - 响应数据的类型* @param url - API 端点地址* @returns 包含泛型类型的 Promise 响应*/
async function fetchData<T>(url: string): Promise<ApiResponse<T>> {const res = await fetch(url)return res.json() // 自动推断类型
}// 用户接口定义
interface User {id: numbername: string
}// 实际应用场景
const userResponse = await fetchData<User>('/api/user/1')if (userResponse.success) {console.log(userResponse.data.name) // ✅ 完全类型安全!
}
在这个案例中,泛型帮助我们:
- 保持不同接口返回数据的类型安全
- 统一错误处理流程
- 实现出色的代码复用
六、总结
泛型的本质是在静态类型系统中引入动态特性,它完美平衡了类型安全与代码复用之间的矛盾。正如 TypeScript 之父 Anders Hejlsberg 所说:“泛型是类型系统的参数化,就像函数是值的参数化”。
掌握泛型的关键在于:
- 理解类型参数化的核心思想
- 识别适合泛型的应用场景
- 保持对代码复杂度的警惕
当你能游刃有余地运用泛型时,就意味着真正理解了 TypeScript 类型系统的精髓。记住: 泛型不是炫技的工具,而是为代码可靠性服务的利器 。合理使用,方显功力。
相关文章:
深入浅出 TypeScript 泛型:类型安全的艺术与实践
文章目录 一、泛型的核心概念1.1 类型参数:代码中的类型变量1.2 类型推断:让代码保持简洁 二、泛型的四大应用场景2.1 泛型函数:打造通用工具库2.2 泛型接口:定义灵活的数据结构2.3 泛型类:构建类型安全的容器2.4 泛型…...
【KWDB创作者计划】_KaiwuDB 2.1.0 单节点裸机部署
大家好,这里是 DBA学习之路,专注于提升数据库运维效率。 目录 前言KWDB 介绍安装准备环境信息配置要求操作系统软件依赖端口要求安装包下载 部署 KWDB简单实用连接数据库创建数据库创建用户创建时序表 前言 今天无意间在墨天轮看到一个征文活动 征文大赛…...
洛谷题单3-P5720 【深基4.例4】一尺之棰-python-流程图重构
题目描述 《庄子》中说到,“一尺之棰,日取其半,万世不竭”。第一天有一根长度为 a a a 的木棍,从第二天开始,每天都要将这根木棍锯掉一半(每次除 2 2 2,向下取整)。第几天的时候木…...
前端快速入门学习3——CSS介绍与选择器
1.概述 CSS全名是cascading style sheets,中文名层叠样式表。 用于定义网页样式和布局的样式表语言。 通过 CSS,你可以指定页面中各个元素的颜色、字体、大小、间距、边框、背景等样式,从而实现更精确的页面设计。 HTML与CSS的关系:HTML相当…...
Redash:一个开源的数据查询与可视化工具
Redash 是一款免费开源的数据可视化与协作工具,可以帮助用户快速连接数据源、编写查询、生成图表并构建交互式仪表盘。它简化了数据探索和共享的过程,尤其适合需要团队协作的数据分析场景。 数据源 Redash 支持各种 SQL、NoSQL、大数据和 API 数据源&am…...
嵌入式Linux驱动—— 1 GPIO配置
目录 1.GPIO操作 1.1 IO命名 1.2 GPIO 时钟使能(CCM) 1.3 IO 复用(IOMUXC) 1.4 IO 配置 1.5 GPIO 配置 1.GPIO操作 GPIO操作主要是以下流程: 使能某组GPIO模块(GPIO1、2、...)&#…...
[ICLR 2025]Biologically Plausible Brain Graph Transformer
论文网址:Biologically Plausible Brain Graph Transformer 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 …...
SpringBoot+MyBatis Plus+PageHelper+vue+mysql 实现用户信息增删改查功能
静态资源展示 (1)静态资源下载 (2)下载后文件放到resources/static 目录下 (3) main函数启动项目访问对应文件,http://127.0.0.1:8080/user-list.html 数据库添加表和数据 SET FOREIGN_KEY_CHECKS0;-- --------…...
企业常用Linux服务搭建
1.需要两台centos 7服务器,一台部署DNS服务器,另一台部署ftp和Samba服务器。 2. 部署DNS 服务器 #!/bin/bash# 更新系统 echo "更新系统..." sudo yum update -y# 安装 BIND 和相关工具 echo "安装 BIND 和相关工具..." sudo y…...
Qwen-7B-Chat 本地化部署使用
通义千问 简介 通义千问是阿里云推出的超大规模语言模型,以下是其优缺点: 优点 强大的基础能力:具备语义理解与抽取、闲聊、上下文对话、生成与创作、知识与百科、代码、逻辑与推理、计算、角色扮演等多种能力。可以续写小说、编写邮件、解…...
QGIS获取建筑矢量图-Able Software R2V
1.QGIS截图 说明:加载天地图矢量图层,然后进行截图。 2.Able Software R2V 说明:Able Software R2V 是一款将光栅图像(如扫描图纸、航拍照片)自动转换为矢量图形(如DXF格式)的软件&a…...
CSS:换行与不换行
一、CSS 不允许换行 在 CSS 中,有几种方法可以控制文本不换行: 1. 使用 white-space 属性 .no-wrap {white-space: nowrap; } white-space: nowrap; 会强制文本在一行显示,不换行。 2. 使用 overflow 和 text-overflow 通常与 white-sp…...
【MiniMind】不能全局用 `pip install --upgrade pip`
Q:WARNING: Running pip as the ‘root’ user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.…...
form实现pdf文件转换成jpg文件
说明: 我希望将pdf文件转换成jpg文件 请去下载并安装 Ghostscript,gs10050w64.exe 配置环境变量:D:\Program Files\gs\gs10.05.0\bin 本地pdf路径:C:\Users\wangrusheng\Documents\name.pdf 输出文件目录:C:\Users\wan…...
STM32单片机入门学习——第13节: [6-1] TIM定时中断
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.04 STM32开发板学习——第13节: [6-1] TIM定时中断 前言开发板说明引用解答和科普一…...
量子纠错码实战:从Shor码到表面码
引言:量子纠错的必要性 量子比特的脆弱性导致其易受退相干和噪声影响,单量子门错误率通常在10⁻~10⁻量级。量子纠错码(QEC)通过冗余编码测量校正的机制,将逻辑量子比特的错误率降低到可容忍水平。本文从首个量子纠错…...
【2】搭建k8s集群系列(二进制)之安装etcd数据库集群
一、etcd服务架构 Etcd 是一个分布式键值存储系统,Kubernetes 使用 Etcd 进行数据存储,所以先 准备一个 Etcd 数据库,为解决 Etcd 单点故障,应采用集群方式部署,这里使用 3 台组建集群,可容忍 1 台机器故障…...
Linux常用命令详解:从基础到进阶
目录 一、引言 二、文件处理相关命令 (一)grep指令 (二)zip/unzip指令 编辑 (三)tar指令 (四)find指令 三、系统管理相关命令 (一)shutdown指…...
【Docker】使用Docker快速部署n8n和unclecode/crawl4ai
Docker部署自动化工具n8n和crawl4ai详细教程 前言 本文将详细介绍如何使用 Docker 来部署和运行自动化工作流工具 n8n 以及 crawl4ai。这两个工具对于需要进行自动化工作流程的开发者来说都非常有用。 一、环境准备 在开始之前,请确保您的系统已经安装了&#x…...
数据库权限获取
1. into outfile(手写) 1.1. 利用条件 • web 目录具有写入权限,能够使用单引号 • 知道网站绝对路径(根目录,或则是根目录往下的目录都行) • secure_file_priv 没有具体值(在 mysql/my.ini 中查看) 1.2. secure_file_priv 介绍 secure_file_priv 是用来限制 loa…...
基于spring boot的外卖系统的设计与实现【如何写论文思路与真正写出论文】
目录 系统开发实现链接: 背景与分析: 背景(题目): 用户功能 配送员功能 管理员功能 分析: 过程(主体展示为主,部分功能不一一展示): 目录 论文前面…...
Kubernetes 存储 Downward API
1.介绍 1.提供容器元数据 比如我们 golang语言 我们说他会根据当前CPU的数量 以此去确认我们的进程 线程 和协程之间的关系 以此去释放我们当前CPU的更大的 这么一个并行任务的能力 但是这里会出现一个问题 容器它是把当前的应用 封装在我们固定的名称空间了 而且给它以特定的…...
使用ctags+nvim自动更新标签文件
ctags是一个强大的语言分析工具,可以分析多种语言并生成语法结构文件,通过这些文件可以快速进行函数跳转,但是这有一个缺点,就是每次在项目里更新了代码之类的比如新增了一个函数,都需要重新使用ctags -R .来重新更新标…...
RK3568 gpio模拟i2c 配置hym8563 RTC时钟
1、使用模拟i2c,确认使用的gpio未被占用,为gpio功能 以GPIO0_C6 GPIO0_C7为例,查看管脚的复用关系。 cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins2、使用内核模块i2c-gpio.c 内核make menuconfig 开启i2c_gpio支持 Device Drivers->I2C sup…...
HANA如何在存储过程里执行动态SQL
业务场景需求: 在HANA里如何实现动态的SQL控制,比如需要多个单据里,实现某个自定义字段不允许重复 一般的写法是需要在每个业务单据里加对应的存储过程控制,这样的话,需要在每个业务单据里进行控制,SQL维…...
01人工智能基础入门
一、AI应用场景和发展历程 1.1行业应用 1、deepdream图像生成、yolo目标检测 2、知识图谱、画风迁移 3、语音识别、计算机视觉 4、用户画像 5、百度人工智能布局 1.2发展历程 人工智能的发展经历了 3 个阶段: 1980年代是正式成形期,尚不具备影响力。 …...
嵌入式AI的本地化部署的好处
嵌入式AI本地化处理(即边缘计算)的核心优势在于将AI算力下沉至设备端,直接处理数据而非依赖云端,这种模式在多个维度上展现出显著价值: 一、数据隐私与安全性提升 1. 敏感数据本地存储 金融、医疗等涉及隐私的行业…...
进程和内存管理
目录 一.进程的基本信息 1.1进程的定义 1.2进程的特征 1.3进程的组成 1.4线程产生的背景 1.5线程的定义 1.6进程与线程的区别 1.7进程的类别 1.8进程的优先级 1.8.1进程优先级的概念 1.8.2PRI和NI 1.9僵尸进程 1.9.1僵尸进程的定义 1.9.2僵尸进程产生的原因 1.9…...
001 vue
https://cn.vuejs.org/ 文章目录 v-bindv-modelv-on修饰符条件渲染/控制:v-if v-show列表渲染 M:即Model,模型,包括数据和一些基本操作 V:即View,视图,页面渲染结果 VM:即View-Mode…...
css动态设置div宽高,calc函数
在css中使用calc函数 calc() 是 CSS 中的一种函数,用于动态计算长度值。它允许你在 CSS 属性中进行数学运算,结合不同的单位(如 px、%、em 等),从而创建更加灵活和响应式的布局 表达式规则 运算符:支持加…...
