TypeScript的泛型是什么,泛型约束是什么?

news2024/12/27 13:32:02

目录

一、泛型定义

二、泛型函数

1. 定义泛型函数

2. 调用泛型函数

3.简化泛型函数调用

三、泛型约束

1. 指定更加具体的类型

2. 添加约束

3.多个类型变量

四、泛型接口


一、泛型定义

在TypeScript中的泛型(Generics)允许我们在保证类型安全前提下参数化类型,以便在使用类、函数或接口时才指定具体的类型。

使用泛型可以增加代码的灵活性和重用性,特别是在处理不确定类型的情况下。它可以帮助我们编写更通用的代码,而不需要针对每种可能的类型都进行重复的实现。

比如有一个需求:创建一个 id 函数,传入什么数据就返回该数据本身(也就是说,参数和返回值类型相同),假如像下面这么写,id(10) 调用以上函数就会直接返回 10 本身。但是,该函数只接收数值类型,无法用于其他类型。

function id(value: number): number { return value }

为了能让函数能够接受任意类型,可以将参数类型修改为 any。但是,这样就失去了 TS 的类型保护,类型不安全。

function id(value: any): any { return value }

泛型在保证类型安全(不丢失类型信息)的同时,可以让函数等与多种不同的类型一起工作,灵活可复用。实际上,在 C# 和 Java 等编程语言中,泛型都是用来实现可复用组件功能的主要工具之一。

二、泛型函数

1. 定义泛型函数

function id<Type>(value: Type): Type { return value }
​
function id<T>(value: T): T { return value }

解释:

  1. 语法:在函数名称的后面添加 <>(尖括号),尖括号中添加类型变量,比如此处的 Type

  2. 类型变量 Type,是一种特殊类型的变量,它处理类型而不是值

  3. 该类型变量相当于一个类型容器,能够捕获用户提供的类型(具体是什么类型由用户调用该函数时指定)

  4. 因为 Type 是类型,因此可以将其作为函数参数和返回值的类型,表示参数和返回值具有相同的类型

  5. 类型变量 Type,可以是任意合法的变量名称

2. 调用泛型函数

const num = id<number>(10)
const str = id<string>('a')

解释:

  1. 语法:在函数名称的后面添加 <>(尖括号),尖括号中指定具体的类型,比如,此处的 number

  2. 当传入类型 number 后,这个类型就会被函数声明时指定的类型变量 Type 捕获到

  3. 此时,Type 的类型就是 number,所以,函数 id 参数和返回值的类型也都是 number

  • 同样,如果传入类型 string,函数 id 参数和返回值的类型就都是 string

  • 这样,通过泛型就做到了让 id 函数与多种不同的类型一起工作,实现了复用的同时保证了类型安全

3.简化泛型函数调用

// 省略 <number> 调用函数
let num = id(10)
let str = id('a')

解释:

  1. 在调用泛型函数时,可以省略 <类型> 来简化泛型函数的调用

  2. 此时,TS 内部会采用一种叫做类型参数推断的机制,来根据传入的实参自动推断出类型变量 Type 的类型

  3. 比如,传入实参 10,TS 会自动推断出变量 num 的类型 number,并作为 Type 的类型

  • 推荐:使用这种简化的方式调用泛型函数,使代码更短,更易于阅读

  • 说明:当编译器无法推断类型或者推断的类型不准确时,就需要显式地传入类型参数

三、泛型约束

默认情况下,泛型函数的类型变量 Type 可以代表多个类型,这导致无法访问任何属性。比如,id('a') 调用函数时获取参数的长度:

function id<Type>(value: Type): Type {
  console.log(value.length)
  return value
}
​
id('a')
// id (10)

Type 可以代表任意类型,无法保证一定存在 length 属性,比如 number 类型就没有 length。此时,就需要为泛型添加约束来收缩类型(缩窄类型取值范围)。

添加泛型约束收缩类型,主要有以下两种方式:1 指定更加具体的类型 2 添加约束

1. 指定更加具体的类型

比如,将类型修改为 Type[](Type 类型的数组),因为只要是数组就一定存在 length 属性,因此就可以访问了。

function id<Type>(value: Type[]): Type[] {
  console.log(value.length)
  return value
}

 

2. 添加约束

  // 创建一个接口
  interface ILength {
    length: number
  }

  // Type extends ILength 添加泛型约束
  // 解释:表示传入的 类型 必须满足 ILength 接口的要求才行,也就是得有一个 number 类型的 length 属性
  function id<Type extends ILength>(value: Type): Type {
    console.log(value.length)
    return value
  }

解释:

  1. 创建描述约束的接口 ILength,该接口要求提供 length 属性

  2. 通过 extends 关键字使用该接口,为泛型(类型变量)添加约束

  3. 该约束表示:传入的类型必须具有 length 属性

  • 注意:传入的实参(比如,数组)只要有 length 属性即可(类型兼容性)

3.多个类型变量

泛型的类型变量可以有多个,并且类型变量之间还可以约束(比如,第二个类型变量受第一个类型变量约束) 比如,创建一个函数来获取对象中属性的值:

<script setup lang="ts">
  function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
    return obj[key]
  }
  const person = { name: 'jack', age: 18 }
  getProp(person, 'name')
</script>

解释:

  1. 添加了第二个类型变量 Key,两个类型变量之间使用 , 逗号分隔。

  2. keyof 关键字接收一个对象类型,生成其键名称(可能是字符串或数字)的联合类型

  3. 本示例中 keyof Type 实际上获取的是 person 对象所有键的联合类型,也就是:'name' | 'age'

  4. 类型变量 Key 受 Type 约束,可以理解为:Key 只能是 Type 所有键中的任意一个,或者说只能访问对象中存在的属性

// Type extends object 表示: Type 应该是一个对象类型,如果不是 对象 类型,就会报错
// 如果要用到 对象 类型,应该用 object ,而不是 Object
function getProperty<Type extends object, Key extends keyof Type>(obj: Type, key: Key) {
  return obj[key]
}

四、泛型接口

接口也可以配合泛型来使用,以增加其灵活性,增强其复用性。

interface IdFunc<Type> {
  id: (value: Type) => Type
  ids: () => Type[]
}
​
let obj: IdFunc<number> = {
  id(value) { return value },
  ids() { return [1, 3, 5] }
}

解释:

  1. 在接口名称的后面添加 <类型变量>,那么,这个接口就变成了泛型接口。

  2. 接口的类型变量,对接口中所有其他成员可见,也就是接口中所有成员都可以使用类型变量

  3. 使用泛型接口时,需要显式指定具体的类型(比如,此处的 IdFunc<nunber>)。

  4. 此时,id 方法的参数和返回值类型都是 number;ids 方法的返回值类型是 number[]。

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

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

相关文章

微信小程序开发--4.2预览文件/图片

预览文件 wx.downloadFile({url:, success (res) {console.log(res)if (res.statusCode 200) {wx.openDocument({filePath: res.tempFilePath, showMenu: true,fileType: "xlsx",//文件类型success: function (res) {},fail:function(err){}})}}}) wx.openDocumen…

IO多线程newfd问题

1&#xff0c;多线程中的newfd&#xff0c;能否修改成全局&#xff1f; 答&#xff1a;不能&#xff0c;代码如下。 一共挂了4个客户端&#xff0c;前3个只能运行1次&#xff0c;第4个客户端可以发送多次。 说明后面的客户端覆盖了之前的客户端。前面的客户端一直阻塞在acce…

【力扣每日一题】2023.8.15 字符中的查找与替换

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目很长&#xff0c;简而言之就是检查字符串中对应索引的位置是否有特定的字符串&#xff0c;如果有&#xff0c;那么替换&#xff0c;返…

点击base64编码过的图片在另一个页面显示

开始的代码是这样的&#xff0c;新开一个窗口显示经过base64编码后的图片&#xff0c;但是url太长了显示失败。 openImage(imgSrc) {window.open(imgSrc, _blank); }, 解决方法&#xff1a;这段代码接收一个Base64编码的图像数据&#xff0c;把它转换为一个Blob对象。 Blob&…

《算法竞赛·快冲300题》每日一题:“房间划分”

《算法竞赛快冲300题》将于2024年出版&#xff0c;是《算法竞赛》的辅助练习册。 所有题目放在自建的OJ New Online Judge。 用C/C、Java、Python三种语言给出代码&#xff0c;以中低档题为主&#xff0c;适合入门、进阶。 文章目录 题目描述题解C代码Java代码Python代码 “ 房…

考公-判断推理-组合排列

例题 例题 例题 代入法 例题 排除法 例题

AMD限制资源用量CU_MASK

通过配置两个环境变量来控制进程所使用的CU&#xff1a; CU_MASK_0 CU_MASK_1 举例&#xff1a; 使用每个ES中的一半CU则配置如下&#xff1a; export CU_MASK_00xcccccccc export CU_MASK_10xcccccccc

判断推理 -- 图形推理 -- 位置规律

一组图&#xff1a;从前往后找规律。 二组图&#xff1a;从第一组图找规律&#xff0c;第二组图应用规律。 九宫格&#xff1a; 90%横着看找规律&#xff0c;第一行找规律&#xff0c;第二行验证规律&#xff0c;第三行应用规律。 所有有元素组成都是线&#xff0c;三角形&…

【C++ STL基础入门】初识STL

文章目录 前言一、STL是什么&#xff1f;1.STL概念2.容器是什么&#xff1f;3.STL的优势 二、将会学习到的stl和算法1.将会学到的容器2.算法3.字符串基础字符串字符串视图(basic_string_view) 总结 前言 本系列STL是以VS2022为编译器&#xff0c;C20为标准来写的一套STL。 ST…

笔记04:全局内存

一、CUDA内存模型概述 寄存器、共享内存、本地内存、常量内存、纹理内存和全局内存 一个核函数中的线程都有自己私有的本地内存。 一个线程块有自己的共享内存&#xff0c;对同一个线程块中所有的线程都可见&#xff0c;其内容持续线程块的整个生命周期。 所有线程都可以访问…

武汉地铁19号线完成5G专网全覆盖,现场测试下行速率超千兆!

近日&#xff0c;极目新闻记者从中国移动湖北公司获悉&#xff0c;随着武汉地铁19号线全线隧道正式贯通&#xff0c;湖北移动目前已完成新月溪公园至鼓架山站5G网络覆盖&#xff0c;轨行区5G专网全覆盖&#xff0c;并成功进行试车验证&#xff0c;19号线成为国内首条全线实现5G…

互联网发展历程:从中继器口不够到集线器的引入

互联网的发展&#xff0c;就像一场不断演进的技术盛宴&#xff0c;每一步的变革都在推动着我们的世界向前。然而&#xff0c;在网络的早期&#xff0c;一项重要的技术问题曾困扰着人们&#xff1a;当中继器的接口数量不足时&#xff0c;如何连接更多的设备&#xff1f;这时&…

C#_Array类型

简介 公共语言运行时中所有数组的基类、抽象类&#xff0c;用于创建、处理、搜索、排序数组。 常用属性 Rank&#xff1a;获取数组维数&#xff08;在多维数组中采用有序整数来标注&#xff0c;例如一维数组、二维数组、三维数组&#xff09;&#xff0c;数量从1开始。 leng…

记录--form 表单恢复初始数据

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 form 表单恢复初始数据 在现代的 Web 开发中&#xff0c;表单是不可或缺的组件之一。用户可以通过表单输入和提交数据&#xff0c;而开发者则需要对这些数据进行处理和存储。然而&#xff0c;在某些情…

web基础入门和PHP语言基础入门 一

web基础入门和php语言基础入门 一 WEB简介与HTTP入门WEB简介HTTP 简介HTTP 请求报文&#xff1a;请求方法&#xff1a;请求头部&#xff1a;&#xff08;常见的请求头&#xff09;HTTP 响应报文&#xff1a;响应状态码&#xff1a;Cookie HTML入门学习什么是HTML什么是标记语言…

调试 SELinux

semanage port -a -t http_port_t -p tcp 82 题目&#xff1a; 非标准端口 82 上运行的 WEB 服务器在提供内容时遇到问题。根据需要调试并解决问题&#xff0c; 并使其满足以下条件&#xff1a; 系统上的 web 服务器能够提供/var/www/html 中所有现在有的 html 文件&#xff…

分享一个使用Java工具类——git格式图片裁剪重组

git格式图片裁剪重组 有时候需要自己录制一个gif图片的时候就不知道去哪里录制&#xff0c;所以只能在百度找一个可以录制gif图片的软件&#xff0c;但是你会发现&#xff0c;你能找到的免费导出的都是有水印的&#xff0c;所以你可能就需要找一个水印少一点的软件了&#xff…

AI黑马挑战赛,探索研发新趋势丨IDCF

随着AI的出现&#xff0c;获取知识的成本大幅降低&#xff0c;当DevOps与AI相结合时&#xff0c;必将产生全新的化学反应。不断涌现的AI新工具提醒我们&#xff0c;一个全新的研发工作范式正在逐渐形成。而DevOps的核心理念是敏捷协同&#xff0c;作为工程师&#xff0c;如何通…

印度通过《2023年数字个人数据保护法案》

2023年8月7日&#xff0c;印度议会下议院&#xff08;Lok Sabha&#xff09;通过《2023年数字个人数据保护法案》&#xff08;Digital Personal Data Protection Bill 2023&#xff09;。8月9日&#xff0c;该法案获得上议院&#xff08;Rajya Sabha&#xff09;批准。 - 该法案…

Leaflet入门,Leaflet如何实现vue双向绑定数据添加到图片标记物到地图上,动态根据vue数据更新到地图上以及鼠标经过标记物显示提示框

前言 本章使用Leaflet的vue2-leaflet或者vue-leaflet插件方式实现vue数据绑定地图数据,实现地图标记物与vue数据的双向联动更新,以及鼠标经过标记物显示提示框功能。 实现效果演示 vue如何使用Leaflet vue2如何使用:《Leaflet入门,如何使用vue2-leaflet实现vue2双向绑定…