泛型

泛型(Generics)是指在定义函数、接口或者类的时候, 不预先指定其类型,而是在使用是手动指定其类型的一种特性。

举个栗子

我们需要创建一个函数, 这个函数会返回任何它传入的值。

正常代码如下:

  1. function identity(arg: any): any {
  2. return arg
  3. }
  4. identity(3) // 3

这代代码编译不会出错,但是存在一个显而易见的缺陷, 就是没有办法约束输出的类型与输入的类型保持一致。

这时,我们可以使用泛型来解决这个问题;

  1. function identity<T>(arg: T): T {
  2. return arg
  3. }
  4. identity(3) // 3

上例中,我们在函数名后面加了 <T>, 其中的 T 表示任意输入的类型, 后面的 T 即表示输出的类型,且与输入保持一致。

当然我们也可以在调用时手动指定输入与输出的类型, 如上述函数指定 string 类型:

  1. identity<number>(3) // 3

泛型约束

在泛型函数内部使用类型变量时, 由于事先并不知道它是那种类型, 所以不能随意操作它的属性和方法:

  1. function loggingIdentity<T>(arg: T): T {
  2. console.log(arg.length) // err
  3. return arg
  4. }

上述函数中 类型 T 上不一定存在 length 属性, 所以编译的时候就报错了。

这时,我们可以的对泛型进行约束,对这个函数传入的值约束必须包含 length 的属性, 这就是泛型约束:

  1. interface lengthwise {
  2. length: number
  3. }
  4. function loggingIdentity<T extends lengthwise>(arg: T): T {
  5. console.log(arg.length) // err
  6. return arg
  7. }
  8. loggingIdentity({a: 1, length: 1}) // 1
  9. loggingIdentity('str') // 3
  10. loggingIdentity(6) // err 传入是参数中未能包含 length 属性

这样我们就可以通过泛型约束的方法对函数传入的参数进行约束限制。

多个参数时也可以在泛型约束中使用类型参数

如你声明了一个类型参数, 它被另一类型参数所约束。现在想要用属性名从对象里湖区这个属性。并且还需确保这个属性存在于这个对象上, 因此需要咋这两个类型之间使用约束,

简单举例来说: 定义一个函数, 接受两个参数 第一个是个对象 obj,第二个个参数是第一参数 key 是对象里面的键名, 需要输入 obj[key]

  1. function getProperty<T, K extends keyof T>(obj: T, key: K) {
  2. return obj[key]
  3. }
  4. let obj = { a: 1, b: 2, c: 3 }
  5. getProperty(obj, 'a') // success
  6. getProperty(obj, 'm') // err obj 中不存在 m 这个参数

泛型接口

  1. interface CreateArrayFunc {
  2. <T>(length: number, value: T): Array<T>
  3. }
  4. let createArr: CreateArrayFunc
  5. createArr = function<T>(length: number, value: T): Array<T> {
  6. let result = T[]: []
  7. for(let i = 0; i < length; i++) {
  8. result[i] = value
  9. }
  10. return result
  11. }
  12. createArray(3, 'x'); // ['x', 'x', 'x']

进一步的, 还可以把泛型参数提前到接口名上:

  1. interface CreateArrayFunc<T> {
  2. (length: number, value: T): Array<T>
  3. }
  4. let createArr: CreateArrayFunc<any>
  5. createArr = function<T>(length: number, value: T): Array<T> {
  6. let result = T[]: []
  7. for(let i = 0; i < length; i++) {
  8. result[i] = value
  9. }
  10. return result
  11. }
  12. createArray(3, 'x'); // ['x', 'x', 'x']

注意: 此时使用泛型接口时, 需要定义泛型的类型

泛型类

与泛型接口类型,泛型也可以定义在类的类型定义中:

  1. class GenericNumber<T> {
  2. zeroValue: T
  3. add: (x: T, y: T) => T
  4. }
  5. let myGenericNumber = new GenericNumber<number>()
  6. myGenericNumber.zeroNumber = 0
  7. myGenericNumber.add = function(x, y) {
  8. return x + y
  9. }

注意: 类有两部分: 静态部分和实例部分。泛型类值的是实例部分的类型,所以类的静态属性不能使用这个泛型类型

泛型参数的默认类型

在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。

  1. function createArr<T = string>(length: number, value: T): Array<T> {
  2. let result: T[] = []
  3. for( let i = 0; i < lenght; i++ ) {
  4. result[i] = value
  5. }
  6. return result
  7. }

ts 学习笔记 - 泛型的更多相关文章

  1. Java学习笔记--泛型

    一个泛型类就是具有一个或者多个类型变量的类. 我们可以只关注泛型,而不会为数据存储的细节而烦恼 . java泛型(一).泛型的基本介绍和使用 http://blog.csdn.net/lonelyro ...

  2. TS学习之泛型

    可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据 不适用泛型的函数 function myfn(args: number): number { return args; } functi ...

  3. TS学习笔记----(一)基础类型

    布尔值: boolean let isDone: boolean = false; 数字: number 和JavaScript一样,TS里的所有数字都是浮点数. 支持十进制和十六进制字面量,TS还支 ...

  4. ts 学习笔记-基础篇

    目录 基础 原始数据类型 布尔值 数字 字符串 空值 Null 和 Undefined 任意值 类型推论 联合类型 接口 数组 函数 类型断言 申明文件 什么是申明文件 三斜线指令 第三方声明文件 内 ...

  5. Java学习笔记——泛型

    假定T不仅要指定接口的类继承.使用下面的方式: public class some<T extends Iterable<T> & Comparable<T>&g ...

  6. Thinking in Java学习笔记-泛型和类型安全的容器

    示例: public class Apple { private static long counter; private final long id = counter++; public long ...

  7. Java 学习笔记 泛型

    泛型 上界匹配 ? extends Number 下界匹配 ? super Number getSimpleName 不包括包名 getName 会包括包名 常和反射联合使用,做框架 Type是一个标 ...

  8. ts 学习笔记 - 类

    目录 类 类的概念 类的用法 属性和方法 类的继承 存取器 静态属性 Typescript 中的用法 抽象类 类的类型 类与接口 类实现接口 接口继承接口 接口继承类 混合类型 类 类的概念 类 (c ...

  9. ts 学习笔记 - 进阶篇 1

    目录 进阶 类型别名 字符串字面量类型 元祖 例子 越界的元素 枚举 手动赋值 常数项和计算所得项 常数枚举 外部枚举 进阶 类型别名 类型别名用来给一个类型起个新名字 type Name = str ...

随机推荐

  1. 全栈工程师知识点汇总——html5(上)

    一.HTML5 1.新特性: 1. 取消了过时的显示效果标记 <font></font> 和 <center></center> ... 2. 新表单元 ...

  2. Linux/Ubuntu正确卸载LXDE

    第一步: sudo apt-get remove lxde 第二步 sudo apt autoremove lxde

  3. ubuntu16.04服务器上无root权限,配置个人tensorflow环境--cuda9.0+cuDNN7+tensorflow-gpu-1.8

    本人在服务器上已经用Anconda创建好python3.5的环境,这个网上有一大堆教程.接下来是重点. 1. cuda的安装 https://developer.nvidia.com/cuda-dow ...

  4. laravel 5.6初学笔记

    laravel 5.6初学笔记 http://note.youdao.com/noteshare?id=bf4b701b49dd035564e7145ba2d978b4 框架简介 laravel文档齐 ...

  5. .gitignore文件我自己常用的配置

    我项目中一般不需要上传到git服务器上的有 .idea ------.idea目录 .mvn ------.mvn目录 .iml mvnw mvnw.cmd logs/ --- 我生成的日志文件目录 ...

  6. 脱壳系列_0_FSG壳_详细版

    ---恢复内容开始--- 1 查看信息 使用ExeInfoPe查看此壳程序 可以看出是很老的FSG壳. 分析: Entry Point : 000000154,熟悉PE结构的知道,入口点(代码)揉进P ...

  7. 【iOS】图片缩放动画

    iOS 开发中,可用 UIView 的下述方法实现图片的缩放动画效果: + transitionWithView:duration:options:animations:completion: 示例代 ...

  8. codeforces 339 D.Xenia and Bit Operations(线段树)

    这个题目属于线段树的点更新区间查询,而且查的是整个区间,其实不用写query()函数,只需要输出根节点保存的值就可以了. 题意: 输入n,m表示有2^n个数和m个更新,每次更新只把p位置的值改成b,然 ...

  9. 浅入深出Vue:自动化路由

    在软件开发的过程中,"自动化"这个词出现的频率是比较高的.自动化测试,自动化数据映射以及各式的代码生成器.这些词语的背后,也说明了在软件开发的过程中,对于那些重复.千篇一律的事情. ...

  10. 夯实Java基础(十二)——异常处理

    1.异常处理概述 在Java程序执行过程中, 总是会发生不被期望的事件, 阻止程序按照程序员预期正常运行, 这就是Java程序出现的异常. 异常处理是基于面向对象的一种运行错误处理机制,通过对异常问题 ...