用这篇指南深入理解TypeScript的泛型特性
最编程
2024-07-27 22:09:10
...
什么是泛型
我们先来看看 ChatGPT 怎么说:
泛型就是 将类型进行传递,然后确保在使用的时候类型正确。
泛型优缺点
优点
- 类型安全:使用泛型可以让代码在编译时就发现类型错误,避免了运行时类型错误的发生。
- 代码复用:泛型可以将一些通用的代码封装成可复用的函数或类,避免了重复编写类似的代码。
- 可读性较好:使用泛型可以增强代码的可读性和可维护性,使代码更加易于理解和修改。
- 提高性能:泛型代码在 TypeScript 中不需要进行额外的类型检查和类型转换,可以提高程序的运行效率。
缺点
- 学习曲线陡峭:与 Java 中一样,使用泛型需要掌握类型参数、泛型方法和通配符等概念,这可能会使初学者感到困惑。
- 约束较强:在 TypeScript 中,泛型的类型参数需要满足一定的约束条件,这可能会限制泛型的使用范围和灵活性。
- 限制了某些操作:与 Java 中类似,在 TypeScript 中使用泛型时,由于类型参数的不确定性,有些操作是不支持的,例如创建泛型数组、使用 instanceof 运算符等。
- 需要考虑类型擦除:与 Java 中类似,泛型在 TypeScript 中也是通过类型擦除实现的,这可能会影响一些泛型代码的实现和设计。
泛型格式
泛型 用 <>
符号标识泛型类型, 一般是 T 作为 泛型变量 。
- 下面代码中,我们定义一个 获取数据的方法
getData
,给它传入了 泛型变量T, 参数类型也是 T, 返回值的类型也是T
function getData<T>(data : T): T {
return data
}
- 调用函数
它有两种调用方式:
- 直接调用,传入参数, 编译器会进行类型推理
- 传入指定类型,然后输入的参数必须和指定的类型一致,不然会报错
type UserInfo = {
id:Number,
name:String,
address:String,
}
interface EmailInfo {
to:String,
from:String,
content:String,
time:Date
}
function getData<T>(data : T): T {
return data
}
console.log(getData("测试"))
// 测试
console.log(getData<UserInfo>({id:1,name:"海军",address:"上海"}))
// { id: 1, name: '海军', address: '上海' }
console.log(getData<EmailInfo>({to:'Amy',from:"John",content:"最近过的好吗",time: new Date()}))
// {
// to: 'Amy',
// from: 'John',
// content: '最近过的好吗',
// time: 2023-04-16T13:52:26.026Z
// }
泛型接口
泛型接口可以这样理解:
当你需要给接口指定类型时,但目前不知道属性类型为什么时,就可以采用泛型接口
你可以给接口指定参数为多个泛型类型,也可以单个;当使用时,明确参数类型即可。
interface GenericIdentityFn<T,S,D> {
id: T,
source:S,
url: D
}
const websiteInfo : GenericIdentityFn<Number,String,String> = {id:2212,source:"爬虫",url:"http://www.sadasd.com"}
console.log(websiteInfo)
// { id: 221241234, source: '爬虫', url: 'http://www.sadasd.com' }
泛型类
什么是泛型类
它规定了类中属性和方法的 类型,而且必须和类型定义的类型保持一致。
泛型类的作用
可以帮助我们确认类的所有属性都在使用相同的类型
使用格式
class 类名<T> {
name!: T;
hobby!: T;
}
# 这样这个类的所有类型为 number
let 实例 = new 类名<number>();
class GenericityA<X>{
sex!: X;
age!: X;
}
let gen = new GenericityA<number>();
// gen.sex = '测试' 报错
gen.age = 3
console.log(gen.age)
泛型约束
接口约束
通过定义接口, 泛型函数继承接口,则参数必须实现接口中的属性,这样就达到了泛型函数的约束。
# 第一种
// 定义接口
interface DataInfo{
title: string,
price: number
}
// 泛型函数 继承接口,进行对参数类型约束, 如果传入的参数中,没有包含接口属性,则编译不通过
function getDataInfos< T extends DataInfo> (obj: T) : T {
return obj
}
let book = {
title: '前端进阶',
price: 50,
author: '小新'
}
console.log(getDataInfos(book)) //{ title: '前端进阶', price: 50, author: '小新' }
类约束
通过给类的泛型指定为另一个类,这样就规定了类泛型的类型都为另一个类
# 第二种
// 通过类来约束
class Login{
username: string;
password: string;
constructor(username: string,password:string){
this.username = username
this.password = password
}
}
class Mysql<T>{
login<T>(info:T):T{
return info
}
}
let x = new Login('admin','12345');
let mysql = new Mysql<Login>();
console.log(mysql.login(x)) //Login { username: 'admin', password: '12345' }
推荐阅读
-
玩转现代TypeScript的高阶指南:深入理解泛型与类型操作艺术
-
用这篇指南深入理解TypeScript的泛型特性
-
深入理解 TypeScript 的泛型机制
-
玩转 TypeScript:深入理解与实际运用中的泛型机制
-
TypeScript新手指南(9):理解TS中的泛型、泛型函数、泛型类和泛型接口
-
玩转 TypeScript:七、深入理解 TypeScript 中的泛型及其迷你版 Map 实例
-
【2022新手指南】Java编程进阶之路 - 六、技术架构篇 ### MySQL索引底层解析与优化实战 - 你会讲解MySQL索引的数据结构吗?性能调优技巧知多少? - Redis深度揭秘:你知道多少?从基础到哨兵、主从复制全梳理 - Redis持久化及哨兵模式详解,还有集群搭建和Leader选举黑箱打开 - Zookeeper是个啥?特性和应用场景大公开 - ZooKeeper集群搭建攻略及 Leader选举、读写一致性、共享锁实现细节 - 探究ZooKeeper中的Leader选举机制及其在分布式环境中的作用 - Zab协议深入剖析:原理、功能与在Zookeeper中的核心地位 - RabbitMQ全方位解读:工作模式、消费限流、可靠投递与配置策略 - 设计者视角:RabbitMQ过期时间、死信队列与延时队列实践指南 - RocketMQ特性和应用场景揭示:理解其精髓与差异化优势 - Kafka详细介绍:特性及广泛应用于实时数据处理的场景解析 - ElasticSearch实力揭秘:特性概述与作为搜索引擎的广泛应用 - MongoDB认知升级:非关系型数据库的优势阐述,安装与使用实战教学 - BIO/NIO/AIO网络模型对比:掌握它们的区别与在网络编程中的实际应用 - Netty带你飞:理解其超快速度背后的秘密,包括线程模型分析 - 网络通信黑科技:Netty编解码原理与常用编解码器的应用,Protostuff实战演示 - 解密Netty粘包与拆包现象,怎样有效应对这一常见问题 - 自定义Netty心跳检测机制,轻松调整检测间隔时间的艺术 - Dubbo轻骑兵介绍:核心特性概览,服务降级实战与其实现益处 - Dubbo三大神器解读:本地存根与本地伪装的实战运用与优势呈现 ----------------------- 七、结语与回顾
-
深入理解系统本质:用Rust探索泛型的力量