当前位置: 首页 > news >正文

TypeScript5-泛型

泛型是 TS 中一个重要的概念,它可以创建可复用的组件,同时保持对类型信息的一致性。

泛型提供了一种方式使得类型可以被参数化,这样就可以创建可以适用于各种数据类型的函数或类,而不仅仅限于一个数据类型。

一、泛型

先来看一个需求:

我有一个 compiler 函数,我希望这个函数可以接收一个字符串或一个字符串数组,返回值也是一个字符串或一个字符串数组,有什么办法?

结合多种编程语言,我们很容易想到几种解决方法:

1. 使用函数重载

在传统的面向对象编程语言中,例如 Java 或 C++,函数重载允许我们使用相同的函数名定义多个函数,只要它们的参数列表(参数的数量或类型)不同即可。在编译过程中,编译器会通过函数调用时的参数列表判断调用哪个重载函数。

在 JavaScript 中,如果尝试使用相同的函数名定义多个函数,后定义的函数将覆盖先定义的函数。

在 TS 中可以函数重载,如我们可以这样做:

function compliler(template: string): string;
function compliler(template: string[]): string[];
function compliler(template: any) {return template;
}
console.log(compliler('abc')); // "abc" 
console.log(compliler(['abc', 'efg'])); // ["abc", "efg"] 
// console.log(compliler(123)); // 报错

在这个例子中,compiler 函数有两个重载签名和一个实现函数。第一个重载签名接受一个字符串类型的参数,返回一个 字符串。第二个重载签名接受一个字符串数组类型的参数,返回一个字符串数组。

实现函数接受任意类型的参数,返回参数本身。这个实现函数必须能兼容所有的重载签名,所有对 compiler 函数的调用都会执行这个实现函数。

需要注意的是,TS 在解析函数重载时,会按照重载签名从上到下的顺序进行匹配,所以在编写重载签名时,应该把最精确的定义放在最前面。

使用这个方法可以解决这个需求,但是这么一个简单的需求,写出的代码看起来很麻烦,让人很不舒服,不够简洁,因此此方案作废。

2. 使用联合类型

使用联合类型也可以解决这个需求。

function compiler(template: string | string[]): string | string[] {return template;
}

我们定义了一个 compiler 函数,有一个字符串类型或字符串数组类型的参数,返回值可以是字符串,也可以是字符串数组。

这个方法和使用函数重载的方法相比,代码简洁了许多。但如果参数类型可以是很多种,比如 template 参数同时也可以是数字类型、布尔类型、数字数组等。虽然可以在参数的类型注解后面继续加上 | number | bool | number[],但这样代码的观感也不是很好。

在这个例子中,传入 compiler 函数的参数类型可以和返回值类型不一致。如果想让返回值的类型和参数的类型一致(如函数重载案例的效果),就可以使用类型变量。

3. 使用类型变量

类型变量是 TS 中的一种特殊的变量,只用于表示类型而不是值。通过使用类型变量,我们可以创建出在多种类型之间都可以共享的函数或组件。

// 类型变量
function compiler <T> (template: T): T {// ...return template;
}

尖括号中的 T 就是类型变量,它可以捕获用户传入的一些类型,允许我们跟踪函数中使用的这些类型的信息。这里我们定义了类型变量 T,就可以在函数定义中使用它。我们定义了参数 template 的类型为 T,返回值类型也为 T,这样就保证了参数类型和返回值类型一致。

在这个案例中,T 可以是任意类型,函数运行时也并不知道 T 是什么类型。、

为了解决这个问题,我们可以在调用函数时指定参数的类型。如下所示:

compiler<string>('123');

这里我们指定了传入的参数类型为字符串,后面传入的 '123' 就是一个字符串。

也可以直接传入 '123',TS 有类型推导机制,在编译时编译器会推导出传入的参数为字符串类型,T 这时也就是字符串类型,返回值的类型也自然就是字符串类型。

// 类型推导
compiler('123');

现在返回去看需求,传入的参数需要是字符串类型或字符串数组类型,我们就可以结合联合类型这样做:

compiler<string | string[]>('123');

这个案例中的 compiler 函数就是一个泛型函数。

二、泛型约束

来看下面的案例:

function compiler <T> (template: T): T {console.log(template.length);// ...return template;
}compiler<string>('123');

编辑器可以通过我们传入的参数 '123' 来推断出 T 为字符串类型,但是编译时仍然会报错:Property 'length' does not exist on type 'T'.,表示类型 T 中不存在 length 这个属性。

我们可以使用继承接口的方法来实现泛型约束,通过接口来指定一个泛型必须具有某些属性或方法。

interface Len {length: number;
}function compiler <T extends Len> (template: T): T {console.log(template.length);// ...return template;
}compiler<string>('123');

这里我们先定义一个接口 Len,接口中有一个属性 length,再让类型变量 T 继承这个接口,编译器知道了类型 T 下有 length 这个变量,即可编译成功。

这里需要注意,使用这种方法,我们传入的这个参数必须要有 length 这个属性,否则会报错。如:

compiler([]); // 0
compiler(false); // 报错

第一行我们传入一个数组,我们都知道,数组是有 length 属性的,因此可以正确运行,输出 0。

第二行我们传入一个 false,为布尔类型,布尔类型没有 length 属性,所以会报错:Argument of type 'boolean' is not assignable to parameter of type 'Len'.,表示布尔类型和接口 Len 不匹配。

如果我们修改 Len 接口,在接口中增加一个 split 属性,类型为 函数:

interface Len {length: number;split: Function;
}

修改 Len 接口后,传入 compiler 的参数必须同时具有 length 属性和 split 函数。因此 compiler([]) 会报错,因为数组不具备 split 方法。

三、总结

使用泛型的优势:

1. 函数和类可以轻松的支持多种类型,增强程序的扩展性。

2. 不必写多条函数重载、联合类型声明,增强代码的可读性。

3. 灵活控制类型之间的约束。

相关文章:

TypeScript5-泛型

泛型是 TS 中一个重要的概念&#xff0c;它可以创建可复用的组件&#xff0c;同时保持对类型信息的一致性。 泛型提供了一种方式使得类型可以被参数化&#xff0c;这样就可以创建可以适用于各种数据类型的函数或类&#xff0c;而不仅仅限于一个数据类型。 一、泛型 先来看一…...

IMX6ULL裸机篇之DDR3的时钟配置

一. MMDC 控制器 对于 I.MX6U 来说&#xff0c;有 DDR 内存控制器&#xff0c;否则的话它怎么连接 DDR 呢&#xff1f;MMDC控制器 就是 I.MX6U 的 DDR内存控制器。 MMDC 外设包含一个内核(MMDC_CORE)和 PHY(MMDC_PHY)&#xff0c;内核和 PHY 的功能如下&#xff1a; MMDC 内…...

PBDB Data Service:Specimens and measurements(标本和测量)

Specimens and measurements&#xff08;标本和测量&#xff09; 描述摘要1. [Single specimen&#xff08;单个标本&#xff09;](https://blog.csdn.net/whitedrogen/article/details/130685099)2. [Add specimen records or update existing records&#xff08;添加标本记录…...

Zookeeper(一)

简介 设计模式角度 Zookeeper&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理大家都关心的数据&#xff0c;然后接受观察者的注册&#xff0c;一旦这些数据的状态发生变化&#xff0c;Zookeeper就将负责通知已经在Zookeeper上注册的那…...

Maven(五):Maven的使用——依赖的测试

Maven&#xff08;五&#xff09;&#xff1a;Maven的使用——依赖的测试 前言一、实验六&#xff1a;测试依赖的范围1、依赖范围1.1 compile 和 test 对比1.2 compile 和 provided 对比1.3 结论 二、实验七&#xff1a;测试依赖的传递性1、依赖的传递性1.1 概念1.2 传递的原则…...

超级独角兽 Databricks 的崛起之路

在数据扩张以及 AI 兴起的时代&#xff0c;数据存储和分析平台拥有巨大价值和能量。 随着互联网数据的爆炸性增长&#xff0c;数据已经成为企业的新型资源&#xff0c;犹如石油般重要。越来越多的企业希望利用各种结构化和非结构化数据来发挥自己的优势。 然而&#xff0c;他…...

python 3.8 + tensorflow 2.4.0 + cuda11.0 的问题

版本匹配 &#x1f517;从源代码构建 | TensorFlow 报错&#xff1a;Could not load dynamic library ‘cupti64_110.dll’; dlerror: cupti64_110.dll not found 是因为我电脑中的 cuda 版本以前是 10&#xff0c;现在是 11.4 &#xff0c;所以需要安装对应版本的 cudatoolk…...

华为杯”研究生数学建模竞赛2021 年中国研究生数学建模竞赛 E 题: 信号干扰下的超宽带(UWB)精确定位问题-参考思路

一、背景 UWB ( Ultra-Wideband )技术也被称之为“超宽带”,又称之为脉冲无线电技术。这是一 种无需任何载波,通过发送纳秒级脉冲而完成数据传输的短距离范围内无线通信技术,并且信 号传输过程中的功耗仅仅有几十 W 。 UWB 因其独有的特点,使其在军事、物联网等各个领…...

Java 中的访问修饰符有什么区别?

Java 中的访问修饰符用于控制类、类的成员变量和方法的访问权限&#xff0c;主要有以下四种&#xff1a; public&#xff1a;公共访问修饰符&#xff0c;可以被任何类访问。public 修饰的类、成员变量和方法可以在任何地方被访问到。 protected&#xff1a;受保护的访问修饰符…...

Go基础篇:接口

目录 前言✨一、什么是接口&#xff1f;二、空接口 interface{}1、eface的定义2、需要注意的问题 三、非空接口1、iface的定义2、itab的定义3、itab缓存 前言✨ 前段时间忙着春招面试&#xff0c;现在也算告一段落&#xff0c;找到一家比较心仪的公司实习&#xff0c;开始慢慢回…...

边缘计算:数字时代的新战场

随着数字化时代的到来&#xff0c;云计算已经成为了各行各业不可或缺的技术支持。但是&#xff0c;由于云计算涉及到数据的传输和存储&#xff0c;对于网络带宽和延迟的要求也非常高&#xff0c;这使得云计算难以满足一些低延迟、高实时性要求的场景。在这种情况下&#xff0c;…...

PBDB Data Service:Fossil occurrences(化石产出记录)

Fossil occurrences&#xff08;化石产出记录&#xff09; 描述摘要1. [Single fossil occurrence&#xff08;单条化石产出记录&#xff09;](https://blog.csdn.net/whitedrogen/article/details/130519180)2. [List of fossil occurrences&#xff08;化石产出记录列表&…...

虾皮Shopee商品详情接口(item_get-根据ID取商品详情)代码封装

item_get-根据ID取商品详情接口 通过代码封装该接口可以拿到商品标题&#xff0c;商品价格&#xff0c;商品促销信息&#xff0c;商品优惠价&#xff0c;商品库存&#xff0c;sku属性&#xff0c;商品图片&#xff0c;desc图片&#xff0c;desc描述&#xff0c;sku图片&#xf…...

原生js手动实现一个多级树状菜单效果(高度可过渡变化) + 模拟el-menu组件实现(简单版)

文章目录 学习链接效果图代码要点 简单模拟el-menu实现TestTree.vueMenu.vueSubMenu.vue 学习链接 vue实现折叠展开收缩动画 - 自己的链接 elment-ui/plus不定高度容器收缩折叠动画组件 - 自己的链接 vue的过渡与动画理解 Vue transition 折叠类动画自动获取隐藏层高度以及…...

RK3568平台开发系列讲解(Linux内存篇)Linux内存管理框架

🚀返回专栏总目录 文章目录 一、内核态内存分配二、用户态内存分配三、内存篇章更新哪些内容沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们一起将整个内存管理的体系串起来。 对于内存的分配需求,可能来自内核态,也可能来自用户态。 一、内核态内存分配…...

你的编程能力从什么时候开始突飞猛进?

关于编程能力突飞猛进的原因和如何突破自己&#xff0c;以下是我的建议。 在过去的几年中&#xff0c;编程领域发生了很多变化。新的语言和技术不断涌现&#xff0c;使得程序员们需要不断学习和提高。作为一名程序员&#xff0c;编程能力的提高是非常重要的&#xff0c;有助于…...

滨州高企认定条件

认定为高新技术企业必须同时满足以下条件&#xff1a; (一)企业在申请认定时需要注册一年以上。 (二)公司通过自主开发、转让、赠与、并购等方式&#xff0c;获得对其主要产品(服务)在技术上发挥核心支持作用的知识产权所有权。 &#xff08;三&#xff09;对企业主要产品(服…...

Azkaban学习——单机版安装与部署

目录 1.解压改名 2.修改装有mysql的虚拟机的my.cnf文件 3.重启装有mysql的虚拟机 4.Datagrip创建azkaban数据库&#xff0c;执行脚本文件 5.修改/opt/soft/azkaban-exec/conf/azkaban.properties文件 6.修改commonprivate.properties 7.传入mysql-connector-java-8.0.29…...

table标签-移动端适配

封装一个组件&#xff0c;该组件需要根据不同设备屏幕宽度自适应调整展示方式。对于 PC 端&#xff0c;以类似 el-table 的形式展示数据&#xff0c;而移动端则以一个类似 item 的形式展示每行数据。 可以先在组件中判断设备类型&#xff0c;如以下示例代码所示&#xff1a; …...

Yolov8改进---注意力机制:DoubleAttention、SKAttention,SENet进阶版本

目录 🏆🏆🏆🏆🏆🏆Yolov8魔术师🏆🏆🏆🏆🏆🏆 1. DoubleAttention 2. SKAttention 3.总结...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...