TypeScript躬行记(4)——泛型
泛型是程序设计语言中的一种风格或范式,相当于类型模板,允许在声明类、接口或函数等成员时忽略类型,而在未来使用时再指定类型,其主要目的是为它们提供有意义的约束,提升代码的可重用性。
一、泛型参数
当一个函数需要能处理多种类型的参数和返回值,并且还得约束它们之间的关系(例如类型要相同)时,就可以采用泛型的语法,如下所示。
function send<T>(data: T): T {
return data;
}
函数名称后面跟了<T>,其中把T称为泛型参数或泛型变量,表示某种数据类型。注意,T只是个占位符,可以命名的更含语义,例如TKey、TValue等。在使用时,既可以指定类型,也可以利用类型推论自动确定类型,如下所示。
send<number>(10); //指定类型
send(10); //类型推论
当需要处理T类型的数组时,可以像下面这么写。
function send<T>(data: T[]): T[] {
return data;
}
send<number>([1, 2, 3]);
当指定一个泛型函数的类型时,需要包含泛型参数,如下所示,其中泛型参数和函数参数的名称都可与定义时的不同。
let func: <U>(data: U) => U = send;
泛型参数还支持传递多个,只需在声明时增加类型占位符即可。在下面的示例中,将T和U合并成了一个元组类型,还有许多其它用法,将在后面讲解。
function send<T, U>(data: [T, U]): [T, U] {
return data;
}
send<number, string>([1, "a"]);
二、泛型接口
在接口中,可利用泛型来约束函数的结构,如下所示,接口中声明的调用签名包含泛型参数。
interface Func {
<T>(str: T): T;
}
function send<T>(str: T): T {
return str;
}
let fn: Func = send;
泛型参数还可以作为接口的一个参数存在,即把用尖括号包裹的泛型参数移到接口名称之后,如下所示。
interface Func<T> {
(str: T): T;
}
function send<T>(str: T): T {
return str;
}
let fn: Func<string> = send;
当把Func接口作为类型使用时,需要向其传入一个类型,例如上面赋值语句中的string。
三、泛型类
泛型类与泛型接口类似,也是在名称后添加泛型参数,如下所示,其中send属性中的“=>”符号不表示箭头函数,而是用来定义方法的返回值类型。
class Person<T> {
name: T;
send: (data: T) => T;
}
在实例化泛型类时,需要为其指定一种类型,如下所示。
let person = new Person<string>();
person.send = function(data) {
return data;
}
注意,类的静态部分不能使用泛型参数。
四、泛型约束
在使用泛型时,由于事先不清楚参数的数据类型,因此不能随意调用它的属性或方法,甚至无法对其使用运算符。在下面的示例中,访问了data的length属性,但由于编译器无法确定它的类型,因此就会报错。
function send<T>(data: T): T {
console.log(data.length);
return data;
}
TypeScript允许为泛型参数添加约束条件,从而就能调用相应的属性或方法了,如下所示,通过extends关键字约束T必须是string的子类型。
function send<T extends string>(data: T): T {
console.log(data.length);
return data;
}
在添加了这个约束之后,send()函数就无法接收数字类型的参数了,如下所示。
send("10"); //正确
send(10); //错误
1)创建类的实例
在使用泛型创建类的工厂函数时,需要声明T类型拥有构造函数,如下所示。
class Programmer { }
function create<T>(ctor: {new(): T}): T {
return new ctor();
}
create(Programmer);
用“{new(): T}”替代原先的类型占位符,表示可以被new运算符实例化,并且得到的是T类型,另一种相同作用的写法如下所示。
function create<T>(ctor: new()=>T): T {
return new ctor();
}
2)多个泛型参数
在TypeScript中,多个泛型参数之间也可以相互约束,如下所示,创建了基类Person和派生类Programmer,并将create()函数中的T约束为U的子类型。
class Person { }
class Programmer extends Person { }
function create<T extends U, U>(target: T, source: U): T {
return target;
}
当传递给create()函数的参数不符合约束条件时,就会在编译阶段报错,如下所示。
create(Programmer, Person); //正确
create(Programmer, 10); //错误
TypeScript躬行记(4)——泛型的更多相关文章
- TypeScript躬行记(1)——数据类型
TypeScript不仅支持JavaScript所包含的数据类型,还额外扩展了许多实用的数据类型,例如枚举.空值.任意值等. 一.JavaScript的数据类型 JavaScript的数据类型包括6种 ...
- TypeScript躬行记(5)——类型兼容性
TypeScript是一种基于结构类型的语言,可根据其成员来描述类型.以结构相同的Person接口和Programmer类为例,如下所示. interface Person { name: strin ...
- TypeScript躬行记(8)——装饰器
装饰器(Decorator)可声明在类及其成员(例如属性.方法等)之上,为它们提供一种标注,用于分离复杂逻辑或附加额外逻辑,其语法形式为@expression.expression是一个会在运行时被调 ...
- TypeScript躬行记(6)——高级类型
本节将对TypeScript中类型的高级特性做详细讲解,包括交叉类型.类型别名.类型保护等. 一.交叉类型 交叉类型(Intersection Type)是将多个类型通过“&”符号合并成一个新 ...
- TypeScript躬行记(2)——接口
在传统的面向对象语言中,接口(Interface)好比协议,它会列出一系列的规则(即对行为进行抽象),再由类来实现这些规则.而TypeScript中的接口更加灵活,除了包含常规的作用之外,它还能扩展其 ...
- TypeScript躬行记(3)——类
类是对对象的抽象,描述了对象的特征和行为,而对象就是类的实例.ES6引入了类的概念(相关内容可参考ES类和ES6类的继承两节),TypeScript在此基础上,不仅根据ES7等规范完善了类的语法,还添 ...
- TypeScript躬行记(7)——命名空间
TypeScript中的命名空间可将那些具有内在联系的接口.类或对象等代码组织在一起,既能隔离作用域,也能避免命名冲突,并且使得代码结构清晰,更易追踪.在命名空间内部,所有实体部分默认都是私有的,需要 ...
- ES6躬行记(1)——let和const
古语云:“纸上得来终觉浅,绝知此事要躬行”.的确,不管看了多少本书,如果自己不实践,那么就很难领会其中的精髓.自己研读过许多ES6相关的书籍和资料,平时工作中也会用到,但在用到时经常需要上搜索引擎中查 ...
- ES6躬行记 笔记
ES6躬行记(18)--迭代器 要实现以下接口## next() ,return,throw 可以用for-of保证迭代对象的正确性 例如 var str = "向
随机推荐
- iptables限速
####限速 限制指定时间包的允许通过数量及并发数-m limit --limit n/{second/minute/hour}:指定时间内的请求速率"n"为速率,后面为时间分别为 ...
- 十三、springboot 优雅集成spring-boot-admin 实现程序监控
前言 我们知道项目的监控是尤为重要的,但是我们如果用jdk 自带的jconsole 和jvisualvm 的话会非常繁琐,且界面不是很友好.之前我们使用了spring boot 项目,但是都没有对项目 ...
- 洛谷$P5329\ [SNOI2019]$字符串 字符串
正解:字符串 解题报告: 传送门$QwQ$ 有两个很妙的方法,分别港下$QwQ$ 首先为了表示方便,这里和题面一样设$s_i$表示去掉第$i$个字母得到的字符串.另设$lcp(i,j)$表示$suf_ ...
- Redo与Undo的理解
本文概要本文的原意是一篇个人学习笔记,为了避免成为草草记录一下的流水账,尝试从给人介绍的角度开写.但在整理的过程中,越来越感觉力不从心,一是细节太多了,原以为足够了解的一个小知识点下可能隐藏了很多细节 ...
- AutoCad 二次开发 Jig操作之墙块的拖动
测试结果: 主要思路:选择一段多段线,使用封装的jig类进行实时拖动,其原理就是在拖动的时候,确定被拖动的边,我是选择离输入第一个点最近的边作为拖动边,有了这条边,就能确定需要实时更改的点了,然后当鼠 ...
- Ant Design中getFieldDecorator方法的特殊用法(小bug)
记录Ant Design中getFieldDecorator方法的特殊的一个用法 了解Ant Design表单的小伙伴都知道,getFieldDecorator在大部分情况下是用来绑定一个控件的,即像 ...
- Java读取数据库中的xml格式内容,解析后修改属性节点内容并写回数据库
直接附代码: 1.测试用的xml内容 <mxGraphModel> <root> <mxCell id="-1" /> <mxCell i ...
- Alodi:环境创建从未如此简单
一个满足你各种想象的快速方便生成临时环境的系统 在『Alodi:为了保密我开发了一个系统』文章中有讲到我们开发了一个系统用来快速生成临时测试环境,短短三个月已有数百个环境被创建,简化了工作,节省了时间 ...
- PGSQL 字符串作为查询参数的处理
刚从mysql转到pgsql,不太熟悉用法,今天在查询的时候有一个查询参数是字符串,一直没有这一列的错误 ERROR: column "A 桥梁" does not exist L ...
- MapGIS注记文字无损转入ArcGIS软件
在GIS软件中,注释是一种十分特殊的对象,虽然各类软件都支持注释,但它却不属于GIS的基本对象.因此通常的格式转换软件,都不对注释对象做特别的支持,我们最常见的Shape文件格式就只有点.线.面要素, ...