前端深入理解Typescript泛型概念


Posted in Javascript onMarch 09, 2020

首先介绍一下泛性的概念

泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。

泛型是指在定义函数,接口或者类的时候,不预先定义好具体的类型,而在使用的时候在指定类型的一种特性。

先举一个简单的例子

假设我们定义一个函数,它可以接收一个number类型做为参数,并且返回一个number类型。

function genericDemo(data: number): number {
  return data;
}

按照以上的写法是没有问题的,但是如果我们要接受一个string并返回一个string呢?如果逻辑一样还要在写一遍吗?就像下面这样。

function genericDemo(data: string): string {  
  return data;
}

这显然代码是很冗余的,我们还有不使用any的写法吗?答案是显然易见的,可以使用范型的写法,就像下面这样。

function genericDemo<T>(data: T):T {
  return data;
}

我们在函数名称genericDemo后面声明了范型变量<T>,他用于捕获调用该函数时传入的参数类型(例如:number),之后我们就可以使用这个类型。 之后我们再次使用了T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。这允许我们跟踪函数里使用的类型的信息。

多个类型参数

我们在定义范型的时候,也可以一次定义多个类型参数,像下面这样。

function swap<T, U>(tuple: [T, U]):[U, T] {
  return [tuple[1], tuple[0]];
}

泛型接口

我们先定义一个范型接口Identities,然后定义一个函数identities()来使用这个范型接口

interface Identities<T, U> {
  id1: T;
  id2: U;
}

我在这里使用T和U作为我们的类型变量来演示任何字母(或有效的字母数字名称的组合)都是有效的类型—除了常规用途之外,您对它们的调用没有任何意义。

我们现在可以将这个接口应用为identity()的返回类型,修改我们的返回类型以符合它。我们还可以console.log这些参数和它们的类型,以便进一步说明:

function identities<T, U> (arg1: T, arg2: U): Identities<T, U> {
  console.log(arg1 + ": " + typeof (arg1));
  console.log(arg2 + ": " + typeof (arg2));
  let identities: Identities<T, U> = {
  id1: arg1,
  id2: arg2
 };
 return identities;
}

我们现在对identity()所做的是将类型T和U传递到函数和identity接口中,从而允许我们定义与参数类型相关的返回类型。

范型变量

使用泛型创建像identity这样的泛型函数时,编译器要求你在函数体必须正确的使用这个通用的类型。 换句话说,你必须把这些参数当做是任意或所有类型。

我们先看下之前例子

function genericDemo<T>(data: T):T {
  return data;
}

如果我们想同时打印出data的长度。 我们很可能会这样做

function genericDemo<T>(data: T):T {
  console.log(data.length); // Error: T doesn't have .length
  return data;
}

如果这么做,编译器会报错说我们使用了data的.length属性,但是没有地方指明data具有这个属性。 记住,这些类型变量代表的是任意类型,所以使用这个函数的人可能传入的是个数字,而数字是没有.length属性的。

现在假设我们想操作T类型的数组而不直接是T。由于我们操作的是数组,所以.length属性是应该存在的。 我们可以像创建其它数组一样创建这个数组:

function genericDemo<T>(data: Array<T>):Array<T> {
  console.log(data.length);
  return data;
}

范型类

我们还可以在类属性和方法的意义上使类泛型。泛型类确保在整个类中一致地使用指定的数据类型。例如下面这种在React Typescript项目中的写法。

interface Props {
  className?: string;
  ...
}

interface State {
  submitted?: bool;
  ...
}

class MyComponent extends React.Component<Props, State> {
  ...
}

我们在这里使用与React组件一起使用的泛型,以确保组件的props和state是类型安全的。

泛型约束

我们先看一个常见的需求,我们要设计一个函数,这个函数接受两个参数,一个参数为对象,另一个参数为对象上的属性,我们通过这两个参数返回这个属性的值,比如:

function getValue(obj: object, key: string){
  return obj[key] // error
}

我们会得到一段报错,这是新手 TypeScript 开发者常常犯的错误,编译器告诉我们,参数 obj 实际上是 {},因此后面的 key 是无法在上面取到任何值的。

因为我们给参数 obj 定义的类型就是 object,在默认情况下它只能是 {},但是我们接受的对象是各种各样的,我们需要一个泛型来表示传入的对象类型,比如T extends object:

function getValue<T extends object>(obj: T, key: string) {
 return obj[key] // error
}

这依然解决不了问题,因为我们第二个参数 key 是不是存在于 obj 上是无法确定的,因此我们需要对这个 key 也进行约束,我们把它约束为只存在于 obj 属性的类型,这个时候需要借助到后面我们会进行学习的索引类型进行实现 <U extends keyof T>,我们用索引类型 keyof T 把传入的对象的属性类型取出生成一个联合类型,这里的泛型 U 被约束在这个联合类型中,这样一来函数就被完整定义了:

function getValue<T extends object, U extends keyof T>(obj: T, key: U) {
 return obj[key] // ok
}

另外提一个多重泛型约束的写法,可以当作拓展:

interface firstInterface {
  first(): number
}

interface secondInterface {
  second(): string
}

class Demo<T extends firstInterface & secondInterface >{
  ...
}

在泛型里使用类类型

在TypeScript使用泛型创建工厂函数时,需要引用构造函数的类类型。比如:

function create<T>(type: {new(): T; }): T {
  return new type();
}

参数type的类型{new(): T}就表示此泛型T是可被构造的,在被实例化后的类型是泛型 T。

总结

到此这篇关于前端深入理解Typescript泛型概念的文章就介绍到这了,更多相关Typescript 泛型内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
在多个页面使用同一个HTML片段的代码
Mar 04 Javascript
JS调用CS里的带参方法实例
Aug 01 Javascript
将查询条件的input、select清空
Jan 14 Javascript
原生js编写autoComplete插件
Apr 13 Javascript
浅析javaScript中的浅拷贝和深拷贝
Feb 15 Javascript
Zepto实现密码的隐藏/显示
Apr 07 Javascript
Vue.js实现输入框绑定的实例代码
Aug 24 Javascript
详细介绍RxJS在Angular中的应用
Sep 23 Javascript
基于bootstrap写的一点localStorage本地储存
Nov 21 Javascript
微信小程序实现的涂鸦功能示例【附源码下载】
Jan 12 Javascript
js回调函数原理与用法案例分析
Mar 04 Javascript
jQuery实现视频展示效果
May 30 jQuery
js实现无缝轮播图效果
Mar 09 #Javascript
js实现无缝轮播图
Mar 09 #Javascript
基于vue+echarts 数据可视化大屏展示的方法示例
Mar 09 #Javascript
原生js实现瀑布流效果
Mar 09 #Javascript
原生JS实现贪吃蛇小游戏
Mar 09 #Javascript
微信小程序 wx.getUserInfo引导用户授权问题实例分析
Mar 09 #Javascript
在Vue中实现随hash改变响应菜单高亮
Mar 09 #Javascript
You might like
基于initPHP的框架介绍
2013/04/18 PHP
php实现的中秋博饼游戏之掷骰子并输出结果功能详解
2017/11/06 PHP
php自动加载代码实例详解
2021/02/26 PHP
jQuery中Form相关知识汇总
2015/01/06 Javascript
jquery利用命名空间移除绑定事件的方法
2015/03/11 Javascript
jquery+css3实现网页背景花瓣随机飘落特效
2015/08/17 Javascript
使用JQuery实现智能表单验证功能
2016/03/08 Javascript
JS 动态加载js文件和css文件 同步/异步的两种简单方式
2016/09/23 Javascript
Angular2使用Angular-CLI快速搭建工程(二)
2017/05/21 Javascript
详解VueJS 数据驱动和依赖追踪分析
2017/07/26 Javascript
微信小程序表单验证form提交错误提示效果
2020/06/19 Javascript
Vue.js页面中有多个input搜索框如何实现防抖操作
2019/11/04 Javascript
Node.JS发送http请求批量检查文件中的网页地址、服务是否有效可用
2019/11/20 Javascript
JavaScript动画实例之粒子文本的实现方法详解
2020/07/28 Javascript
elementUI同一页面展示多个Dialog的实现
2020/11/19 Javascript
10分钟学会js处理json的常用方法
2020/12/06 Javascript
微信小程序tab左右滑动切换功能的实现代码
2021/02/08 Javascript
Python中super关键字用法实例分析
2015/05/28 Python
批量将ppt转换为pdf的Python代码 只要27行!
2018/02/26 Python
Python简单读写Xls格式文档的方法示例
2018/08/17 Python
解决Pyinstaller 打包exe文件 取消dos窗口(黑框框)的问题
2019/06/21 Python
对python中不同模块(函数、类、变量)的调用详解
2019/07/16 Python
python 魔法函数实例及解析
2019/09/25 Python
Python实现钉钉订阅消息功能
2020/01/14 Python
Python3爬虫中识别图形验证码的实例讲解
2020/07/30 Python
pandas apply多线程实现代码
2020/08/17 Python
摩顿布朗英国官方网上商店:奢华沐浴、身体和头发护理
2016/10/29 全球购物
AMAVII眼镜官网:时尚和设计师太阳镜
2019/05/05 全球购物
国贸专业毕业求职信
2014/06/11 职场文书
采购部长岗位职责
2014/06/13 职场文书
2015年教师党员公开承诺书
2015/01/22 职场文书
开场白怎么写
2015/06/01 职场文书
优秀教师工作总结2015
2015/07/22 职场文书
小学体育教学随笔
2015/08/14 职场文书
Django集成富文本编辑器summernote的实现步骤
2021/05/31 Python
MongoDB安装使用并实现Python操作数据库
2021/06/28 MongoDB