探索 TypeScript 元组的用例
元组扩展了数组数据类型的功能。使用元组,我们可以轻松构造特殊类型的数组,其中元素相对于索引或位置是固定类型的。由于 TypeScript 的性质,这些元素类型在初始化时是已知的。使用元组,我们可以定义可以存储在数组中每个位置的数据类型。
在本教程中,我们将介绍 TypeScript 中命名元组的实际用例和应用程序。我们将了解这种数据类型的重要性以及为什么在某些情况下首选它。在一天结束时,我们将看到这种数据类型如何有助于改进 TypeScript 语言,根据改进的文档、可维护的代码和开发人员的生产力允许更严格的规则。
在我们开始之前,读者应该熟悉TypeScript和类型的基础知识。要了解有关此主题的更多信息,请查看 TypeScript 文档的这一部分。现在,让我们开始吧。
什么是元组?
元组就像具有额外功能的高级数组,可确保类型安全,特别是当我们需要考虑包含具有多个已知类型的固定数量的元素的列表时。
数组和元组之间的主要区别在于,当我们为元组赋值时,这些值必须以相同的顺序与元组声明中定义的类型匹配。另一方面,数组可以支持具有any
类型或按位 OR ( | )
运算符的多种类型,但元素的顺序或结构不起作用。
什么是命名元组?
命名元组提供了一种结构化方法,用于定义具有命名属性的数据。命名元组结合了数组和对象的优点,以清晰简洁的方式表示数据点。此外,命名元组增强了代码的可读性,并通过为属性分配名称来明确您的意图。
若要在 TypeScript 中定义命名元组,请使用方括号和类型注释的组合来指定属性的名称和类型。下面介绍如何在 TypeScript 中定义命名类型:
type MyNamedTuple = [name: string, age: number, isAdmin: boolean];
您已经定义了一个 MyNamedTuple
具有三个属性的命名元组:name
的类型 string
,age
的类型number
、 isAdmin
的类型boolean
。类型定义中属性的顺序决定了实例化时元组中元素的顺序。
定义命名元组类型后,可以通过为属性赋值来声明和初始化该类型的变量,如下所示:
const person: MyNamedTuple = ['John Doe', 30, false];
您声明了该 MyNamedTuple
类型的变量 person
并为其分配了值。值的顺序对应于命名元组中定义的属性顺序。
使用元组的好处
在 TypeScript 程序中使用元组有很多好处。首先,元组是固定长度的序列,允许您定义元素的有序集合。当您需要表示一系列值(如坐标 ( x , y )
或 RGB 颜色值 ( red , green , blue )
时,元组很方便。固定长度有助于确保元组中具有正确数量的元素。
此外,您可以轻松地解构元组以提取单个元素,从而可以方便地使用一行代码将每个元素分配给单独的变量。解构元组可以提高可读性,尤其是在使用返回多个值的函数时。
此外,元组与数组有一些相似之处;您可以对它们执行类似数组的操作。您可以按索引访问单个元素,使用循环迭代它们并使用 map
、 filter
和 reduce
。但是,与数组不同,元组具有固定长度,这可确保元组的结构保持不变。下面是一个示例:
// Declare a tuple type
type MyTuple = [number, string, boolean];// Create a tuple
const myTuple: MyTuple = [10, "Hello", true];// Iterate over tuple elements with a loop
for (const element of myTuple) {console.log(element);
}// Use methods like map, filter, and reduce
const mappedTuple: MyTuple = myTuple.map((element) => element * 2);
console.log(mappedTuple); // Output: [20, "HelloHello", NaN]const filteredTuple: MyTuple = myTuple.filter((element) => typeof element === "string");
console.log(filteredTuple); // Output: [NaN, "Hello", NaN]const reducedValue: number = myTuple.reduce((acc, curr) => acc + (typeof curr === "number" ? curr : 0), 0);
console.log(reducedValue); // Output: 10
以下是在元组上运行常用数组操作的结果:
由于元组的优点和功能,元组优先于数组。元组强制实施固定长度,提供类型安全性,并允许异构数据。TypeScript 支持元组上的结构模式匹配,并启用简洁的函数签名。
解构赋值、只读属性和内存效率是额外的好处。类型推理和命名元组元素使元组对于结构化数据非常强大。
数组和元组数据类型简介
在我们开始探索 TypeScript 中元组的用例之前,让我们简要探讨一些可以使用数组的简单案例,以及元组如何在同一场景中完美地适应甚至更好。
在 TypeScript 中,我们可以声明一个特定数据类型的数组。例如,我们可以通过指定该元素的类型后跟方括号来声明一个数字数组:[]
。让我们看看如何做到这一点:
let arr: number[];arr = [1, 2, 3];
正如我们从上面的例子中看到的,为了确保类型安全(这允许更容易地注释和记录我们的代码),我们需要使用数组,这允许像这样的情况,我们有特定数据类型的列表。事实上,这就是像TypeScript这样的类型语言的本质。
具有多种数据类型的数组
对于具有多种数据类型的数组,我们可以使用 any
类型或 | (按位 OR)
运算符。但是,在这种情况下,数据的顺序不是一成不变的。让我们看下面的一个例子:
let arr: (string | number)[];
arr = ['Alex', 2020];
console.log(arr);
从上面的例子中,我们可以决定在字符串之前传递数字,它仍然有效。在这种情况下,实例化数组时传递数据的顺序无关紧要,因为我们具有指定类型的组合。这正是元组想要解决的问题。
使用元组,我们可以拥有一个多种数据类型的列表,其中我们传递数据类型的顺序必须符合声明元组时的顺序。本质上,元组的结构需要保持不变。让我们看一个例子来更好地理解这个概念:
let tup: [string, number];tup = ['Alex', 19087]
在上面的例子中,我们可以看到我们已经声明了一个具有两种基本数据类型的元组:string
和 number
。请注意,当我们调用变量tup
时,我们还必须按照声明的顺序传递元素类型。本质上,我们不能在索引为0处有一个数字和索引为1处有一个字符串,就像这样:
tup = [19087, 'Alex]
如果我们这样做了,我们将得到如下所示的错误:
TSError: ⨯ Unable to compile TypeScript:
index.ts:6:8 - error TS2322: Type 'number' is not assignable to type 'string'.6 tup = [19087, 'Alex']~~~~~
index.ts:6:15 - error TS2322: Type 'string' is not assignable to type 'number'.6 tup = [19087, 'Alex']
正如我们从上面前面的例子中看到的,我们正在声明一个数字数组并用值初始化它。只要我们只处理数字的元素类型,这就可以工作。为了考虑具有多种数据类型的数组,我们可以使用 any
类型或运算符,尽管在这种情况下,不能保证数据的顺序或 |
结构,这可能不是我们想要的。
但是,使用元组,我们可以确保数据类型和要传递的数据顺序的严格性。元组允许在具有固定数量的元素的元素类型周围指定已知类型边界。
TypeScript 元组用例
由于元组允许我们在数组中定义固定类型和顺序,因此在处理以顺序方式相互关联的数据(其中顺序很重要)时,它们是最好的选择。这样,我们可以轻松地以预定的方式访问元素,从而使我们期望的响应在行为上可预测。
下面,我们将基于 v4.2 版本在 TypeScript 中探索元组类型的更多用例,这些用例通常围绕在函数签名中提取和传播参数列表。
在 REST 参数中使用元组
REST
参数语法将参数收集到单个数组变量中,然后展开它们。在最近的 TypeScript 版本中,我们现在可以使用元组类型将 REST
参数扩展为离散参数。这意味着,当类型 tuple
用作REST
参数时,它会平展到参数列表的其余部分。
简单来说,当 REST 参数是元组类型时,元组类型可以扩展为一系列参数列表。
请考虑以下示例:
declare function example(...args: [string, number]): void;
REST
参数将元组类型的元素扩展为离散参数。调用函数时, args
表示为 REST
参数的函数将展开为与下面的函数签名完全相同:
declare function example(args0: string, args1: number): void;
因此,REST
参数语法收集溢出到数组或元组中的参数。总之,元组类型迫使我们将适当的类型传递给相应的函数签名。TypeScript v4.2 增加了在前导或中间元素上展开的功能。这很方便,因为您可以使用 REST
参数在前导或中间参数上创建可变参数函数,如下所示:
type Matches = [string, boolean];const arsenal: Matches = ['Man City', true];
const city: Matches = ['Man United', true];
const hotspur: Matches = ['Liverpool', true];function processMatches(...matches: [...Matches[], string]): void {const lastMatch = matches.pop();console.log('Previous matches:');for (const match of matches) {console.log(match[0]);}console.log('Last match:', lastMatch);
}processMatches(arsenal, city, hotspur, 'Chelsea vs. Arsenal');
该 processMatches
函数接受具有展开语法的 ...
可变参数。该参数是 ,[...Matches[], string]
这意味着它需要两个或多个类型的 Matches
元组,后跟一个字符串。
使用元组展开表达式
扩展语法将数组或对象的元素扩展为其元素。扩展运算符还可以扩展元组的元素。当函数调用包含元组类型的扩展表达式作为参数时,扩展表达式将扩展为与元组类型的元素对应的参数序列。让我们看下面的一个例子:
type Value = [number, number];const sample = (...value: Value) => {// do something with value here
};// create a type
let sampleTuple: Value;sampleTuple = [20, 40];// Passing the values as literals:
sample(20, 40);// Passing indexes to the corresponding sampleTuple tuple
sample(sampleTuple[0], sampleTuple[1]);// Using the spread operator to pass the full sampleTuple tuple
sample(...sampleTuple);
注意,从上面的例子中我们可以看到,我们已经声明了一个元组类型,并将其作为参数传递给函数签名。
当函数被调用时,我们可以将参数作为文字或通过它们各自的索引传递。但是,使用 spread
运算符是将元组作为参数传递给函数调用的快速而干净的选项。由于扩散运算符的性质,参数被扩展为对应于元组类型元素的参数列表。
解构值
因为元组是底层的数组,我们可以像解构数组一样解构它们。重要的是要注意,解构变量获取相应元组元素的类型。让我们看一个例子:
let tuple: [number, string, boolean];tuple = [7, "hello", true];let [a, b, c] = tuple; // a: number, b: string, c: boolean
TypeScript 元组最佳实践
虽然元组有其优点,但在使用元组之前必须考虑权衡。元组不如数组和对象灵活,修改或扩展元组可能很麻烦。如果数据结构需要频繁修改或其他属性,您可能会发现数组或对象更合适。
创建有意义且可重用的元组类型的提示
创建定义明确且可重用的元组类型对于保持清晰度和减少代码重复至关重要。让我们讨论在 TypeScript 中定义和使用元组类型时要考虑的一些技巧。首先,请确保为元组中的元素分配有意义的名称,以提高可读性并帮助其他人了解每个值的用途。例如,请考虑 [x, y]`` [latitude, longitude]
。
此外,TypeScript 的类型推断系统可以根据元组类型的分配值自动推断元组类型。不应显式定义类型,而应依靠类型推断来减少冗余并提高代码可维护性。如果元组中的某些元素是可选的,请使用联合类型来指示可能存在的元素。灵活性可确保元组类型适应多种方案。
当元组很复杂或跨代码库的多个部分重用时,请考虑将它们抽象为接口或类型别名以实现可重用性,提高代码可读性,并允许将来更易于访问的修改和扩展。通过遵循这些提示,您可以创建有意义且可重用的元组类型,以增强 TypeScript 程序的清晰度和可维护性。
使用元组时要避免的错误
开发人员应注意一些常见的陷阱,以避免潜在的问题。在本节中,我们将介绍使用元组时要避免的一些常见错误。默认情况下,元组是不可变的。尝试修改元组的值将导致编译错误。避免直接更改元组元素;创建具有所需修改的新元组。
请记住,元组依赖于其元素的顺序来维护其结构。意外地对元素重新排序可能会引入难以发现的错误。为了防止这种情况,请使用清晰的描述性变量名称,并使用解构或命名元组元素按名称访问值,而不是仅依赖它们的顺序。
最后,过度使用元组会使代码更难理解和维护。如果数据结构需要频繁修改,请考虑使用对象或数组。避免这些错误将帮助您有效地利用 TypeScript 元组的强大功能并减少潜在的代码错误。
总结
TypeScript 元组就像具有固定数量的元素的数组。它们为我们提供了一个固定大小的容器,可以存储多种类型的值,其中顺序和结构非常重要。当我们确切地知道数组中允许多少种类型时,最好使用此数据类型。众所周知,在原始定义的长度之外分配索引将导致 TypeScript 编译器出错。
请注意,虽然可以通过元组元素的索引修改元组元素的值,但我们必须确保与声明元组变量时提供的类型匹配。这是因为一旦声明,我们就无法更改元组中元素的类型甚至大小。
通过我们在这篇文章中强调的功能,可以设计强类型的高阶函数,这些函数可以转换函数及其参数列表,并且本质上确保一个健壮的、有据可查的、可维护的代码库,这是我们使用 TypeScript 的核心。
相关文章:

探索 TypeScript 元组的用例
元组扩展了数组数据类型的功能。使用元组,我们可以轻松构造特殊类型的数组,其中元素相对于索引或位置是固定类型的。由于 TypeScript 的性质,这些元素类型在初始化时是已知的。使用元组,我们可以定义可以存储在数组中每个位置的数…...
Pytorch使用NN神经网络模型实现经典波士顿boston房价预测问题
Pytorch使用多层神经网络模型实现经典波士顿boston房价预测问题 波士顿房价数据集介绍 波士顿房价数据集是一个经典的机器学习数据集,用于预测波士顿地区房屋的中位数价格。该数据集包含了506个样本,每个样本有13个特征,包括城镇的各种指标&…...

微服务间消息传递
微服务间消息传递 微服务是一种软件开发架构,它将一个大型应用程序拆分为一系列小型、独立的服务。每个服务都可以独立开发、部署和扩展,并通过轻量级的通信机制进行交互。 应用开发 common模块中包含服务提供者和服务消费者共享的内容provider模块是…...

python——案例16:约瑟夫生者死者链队列
约瑟夫游戏的大意是:一条船上有30个人,因为在海上遇到风暴 因此船长告诉乘客,必须牺牲15个人,并议定30个人围成一圈, 由第一个人数起,依次报数,数到第9人,便把他投入大海中ÿ…...

【人工智能前沿弄潮】—— 玩转SAM(Segment Anything)
玩转SAM(Segment Anything) 官网链接: Segment Anything | Meta AI (segment-anything.com) github链接: facebookresearch/segment-anything: The repository provides code for running inference with the SegmentAnything Model (SAM), links fo…...
每日一题——合并两个有序的数组
题目 给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组 数据范围:0≤n,m≤100,∣Ai∣<100,∣Bi∣<100 注意: 1.保证 A 数组有足够的空间存放 B …...

MPP架构和Hadoop架构的区别
1. 架构的介绍 mpp架构是将许多数据库通过网络连接起来,相当于将一个个垂直系统横向连接,形成一个统一对外的服务的分布式数据库系统。每个节点由一个单机数据库系统独立管理和操作该物理机上的的所有资源(CPU,内存等)…...

Java02-迭代器,数据结构,List,Set ,Map,Collections工具类
目录 什么是遍历? 一、Collection集合的遍历方式 1.迭代器遍历 方法 流程 案例 2. foreach(增强for循环)遍历 案例 3.Lamdba表达式遍历 案例 二、数据结构 数据结构介绍 常见数据结构 栈(Stack) 队列&a…...

福布斯发布2023云计算100强榜单,全球流程挖掘领导者Celonis排名17
近日,全球流程挖掘领导者Celonis入选福布斯2023 年云计算 100 强榜单,估值130亿美元,排名第17,Celonis已经是连续三年跻身榜单前20名。 本次榜单由福布斯与Bessemer Venture Partners和Salesforce Ventures联合发布,旨…...

计算机网络 MAC地址
...

Jay17 2023.8.10日报
笔记 【python反序列化】 序列化 类对象->字节流(字符串) 反序列化 字节流->对象 python反序列化没PHP这么灵活,没这么多魔术方法。 import pickle import os class ctfshow(): def init(self): self.username0 self.password0 d…...

Winform中DatagridView 表头实现一个加上一个checkBox,实现全选选项功能
实现效果 点击checkBox1或者直接在第一列列表头点击即可实现 代码实现 我的datagridview叫dgv 我在datagridview已经默认添加了一个DataGridViewCheckBoxColumn,勾选时value为1,不勾选时value为0 第一种通过可视化拖动一个checkBox来实现 拖动组…...

rust基础
这是笔者学习rust的学习笔记(如有谬误,请君轻喷) 参考视频: https://www.bilibili.com/video/BV1hp4y1k7SV参考书籍:rust程序设计语言:https://rust.bootcss.com/title-page.htmlmarkdown地址:h…...

剑指offer39.数组中出现次数超过一半的数字
这个题非常简单,解法有很多种,我用的是HashMap记录每个元素出现的次数,只要次数大于数组长度的一半就返回。下面是我的代码: class Solution {public int majorityElement(int[] nums) {int len nums.length/2;HashMap<Integ…...
spring技术栈面试题
1 Spring支持的事务管理类型有哪些?你在项目中使用哪种方式? Spring支持两种类型的事务管理: 编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。声明式事务管理&#x…...
Android Glide MemorySizeCalculator计算值,Kotlin
Android Glide MemorySizeCalculator计算值,Kotlin for (i in 100..1000 step 50) {val calculator MemorySizeCalculator.Builder(this).setMemoryCacheScreens(i.toFloat()).setBitmapPoolScreens(i.toFloat()).setMaxSizeMultiplier(0.8f).setLowMemoryMaxSizeMultiplier(0…...

KEIL自带的Jlink怎么升级更换版本
问题背景 V4.20以上的keil安装包中都自带Jlink驱动包,即当你安装了KEIL后,Debug或Download就是用的安装KEIL时附带安装的Jlink版本。 那如果存在这种情况,你正在开发的芯片比较新,只有比较新的Jlink驱动软件才能支持,…...

图的遍历之 深度优先搜索和广度优先搜索
深度优先搜索的图文介绍 1. 深度优先搜索介绍 图的深度优先搜索(Depth First Search),和树的先序遍历比较类似。 它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各…...
Java学习笔记27——file类
File类 概述和构造方法概述构造方法 File的创建功能File类判断和获取功能File的删除功能 概述和构造方法 概述 在java.io下 具体的类 file是文件和目录路径名的抽象表示 文件和目录是可以封装成对象的对于file而言,其封装的并不是真正存在的文件(可以…...

细胞——求细胞数量 C++详解
细胞——求细胞数量 C详解 求细胞数量题目描述输入格式输出格式样例样例输入样例输出 提示数据规模与约定 解法代码 求细胞数量 题目描述 一矩形阵列由数字 0 0 0 到 9 9 9 组成,数字 1 1 1 到 9 9 9 代表细胞,细胞的定义为沿细胞数字上下左右若还…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...