面试官:说说你对 TypeScript 中泛型的理解?应用场景?
一、是什么
泛型程序设计(generic programming)是程序设计语言的一种风格或范式
泛型允许我们在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型 在typescript
中,定义函数,接口或者类的时候,不预先定义好具体的类型,而在使用的时候在指定类型的一种特性
假设我们用一个函数,它可接受一个 number
参数并返回一个number
参数,如下写法:
function returnItem (para: number): number {
return para
}
如果我们打算接受一个 string
类型,然后再返回 string
类型,则如下写法:
function returnItem (para: string): string {
return para
}
上述两种编写方式,存在一个最明显的问题在于,代码重复度比较高
虽然可以使用 any
类型去替代,但这也并不是很好的方案,因为我们的目的是接收什么类型的参数返回什么类型的参数,即在运行时传入参数我们才能确定类型
这种情况就可以使用泛型,如下所示:
function returnItem<T>(para: T): T {
return para
}
可以看到,泛型给予开发者创造灵活、可重用代码的能力
二、使用方式
泛型通过<>
的形式进行表述,可以声明:
函数
接口
类
函数声明
声明函数的形式如下:
function returnItem<T>(para: T): T {
return para
}
定义泛型的时候,可以一次定义「多个类型参数」,比如我们可以同时定义泛型 T
和 泛型 U
:
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
swap([7, 'seven']); // ['seven', 7]
接口声明
声明接口的形式如下:
interface ReturnItemFn<T> {
(para: T): T
}
那么当我们想传入一个number作为参数的时候,就可以这样声明函数:
const returnItem: ReturnItemFn<number> = para => para
类声明
使用泛型声明类的时候,既可以作用于类本身,也可以作用于类的成员函数
下面简单实现一个元素同类型的栈结构,如下所示:
class Stack<T> {
private arr: T[] = []
public push(item: T) {
this.arr.push(item)
}
public pop() {
this.arr.pop()
}
}
使用方式如下:
const stack = new Stacn<number>()
如果上述只能传递 string
和 number
类型,这时候就可以使用 <T extends xx>
的方式猜实现「约束泛型」,如下所示:
除了上述的形式,泛型更高级的使用如下:
例如要设计一个函数,这个函数接受两个参数,一个参数为对象,另一个参数为对象上的属性,我们通过这两个参数返回这个属性的值
这时候就设计到泛型的索引类型和约束类型共同实现
索引类型、约束类型
索引类型 keyof T
把传入的对象的属性类型取出生成一个联合类型,这里的泛型 U 被约束在这个联合类型中,如下所示:
function getValue<T extends object, U extends keyof T>(obj: T, key: U) {
return obj[key] // ok
}
上述为什么需要使用泛型约束,而不是直接定义第一个参数为 object
类型,是因为默认情况 object
指的是{}
,而我们接收的对象是各种各样的,一个泛型来表示传入的对象类型,比如 T extends object
使用如下图所示:
多类型约束
例如如下需要实现两个接口的类型约束:
interface FirstInterface {
doSomething(): number
}
interface SecondInterface {
doSomethingElse(): string
}
可以创建一个接口继承上述两个接口,如下:
interface ChildInterface extends FirstInterface, SecondInterface {
}
正确使用如下:
class Demo<T extends ChildInterface> {
private genericProperty: T
constructor(genericProperty: T) {
this.genericProperty = genericProperty
}
useT() {
this.genericProperty.doSomething()
this.genericProperty.doSomethingElse()
}
}
通过泛型约束就可以达到多类型约束的目的
三、应用场景
通过上面初步的了解,后述在编写 typescript
的时候,定义函数,接口或者类的时候,不预先定义好具体的类型,而在使用的时候在指定类型的一种特性的时候,这种情况下就可以使用泛型
灵活的使用泛型定义类型,是掌握typescript
必经之路
参考文献
https://www.tslang.cn/docs/handbook/generics.html
--The End--
系列正在更新:7/12
点击下方卡片解锁更多
创作不易,星标、点赞、在看 三连支持
推荐阅读
-
面试官:说说你对 TypeScript 中泛型的理解?应用场景?
-
【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三大神器解读:本地存根与本地伪装的实战运用与优势呈现 ----------------------- 七、结语与回顾