泛型 - 8


泛型

  • 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
  • 泛型T作用域只限于函数内部使用

什么叫泛型?在定义一个值的类型的时候,先不指定具体的类型,在执行的时候,才确定具体的类型。
什么时候用泛型?定义函数、类

1 泛型函数

为什么会有泛型,它的意义在哪里???看下面这个例子
首先,我们来实现一个函数 createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值

namespace a {
  function createArray(length: number, value: any): Array<any> {
    let result: Array<any> = [];
    for (let i = 0; i < length; i++) {
      result[i] = 1
    }
    return result
  }

  let result = createArray(3, "x");
  console.log(result);
}

在上面这个例子中,value 无法确定类型,导致返回的数组中的类型不能确定,我传入的是个字符串的数组,返回的是数字的数组。
此时可以使用泛型,让其接受了什么类型,就返回指定的类型。

namespace b {
  function createArray<T>(length: number, value: T): Array<T> {
    let result: Array<T> = [];
    for (let i = 0; i < length; i++) {
      // result[i] = 1 // <string> 传入 <T>, 表示一定要是 string 类型的,这里赋值一个数字类型的就会报错
      result[i] = value;
    }
    return result
  }

  let result = createArray<string>(3, "x");
  console.log(result);
}

泛型存在 作用域 的概念,它在确定类型之后,只在函数内部被确定使用。也就是我们是可以在外部多次定义T的类型。

namespace c {
  function createArray<T>(length: number, value: T): Array<T> {
    let result: Array<T> = [];
    for (let i = 0; i < length; i++) {
      // result[i] = 1 // <string> 传入 <T>, 表示一定要是 string 类型的,这里赋值一个数字类型的就会报错
      result[i] = value;
    }
    return result
  }

  let result = createArray<string>(3, "x");
  console.log(result); // ["x", "x", "x"]

  let result2 = createArray<number>(3, 3); // <number>就相当于一个参数,传递给<T>
  console.log(result2); // [3, 3, 3]
}

2 类数组 ArrayLike (比如:arguments)

function sum(...args2: any[]) {
let args: IArguments = arguments;
for (let i = 0; i < args.length; i++) {
console.log(args[i]);
}
}
sum(1, 2, '3');

let root: HTMLElement | null = document.getElementById("root");
let children: HTMLCollection = root!.children
let childNodes: NodeListOf = root!.childNodes

3 类的泛型

class MayArray<T>{
  private list: T[] = [];
  add(val: T) {
    this.list.push(val)
  }
  getMax(): T {
    let result: T = this.list[0];
    for (let i = 0; i < this.list.length; i++) {
      if (this.list[i] > result) {
        result = this.list[i]
      }
    }
    return result;
  }
}

let arr = new MayArray<number>();
arr.add(1);
arr.add(2);
arr.add(3);
let result = arr.getMax();
console.log(result);

4 接口泛型

namespace c {
  interface Calculate {
    <T>(a: T, b: T): T
  }
  let add: Calculate = function <T>(a: T, b: T) {
    return a + b; // 报错,泛型不能进行相加,因为泛型 T 的是无法确定类型的。
  }
  let result = add<number>(1, 2)
  console.log(result);
}

5 多个类型参数

我们通过下面这道题来展示多个类型参数是如何使用的。
题目是:如何在不增加中间变量的情况下,交换两个变量的值

function swap<A, B>(tuple: [A, B]): [B, A] {
  return [tuple[1], tuple[0]]
}
let result1 = swap<string, number>(["xx", 12])
console.log(result1);

6 默认泛型类型

和函数形参可以接受默认值是一样,用<T = number>来表述默认类型

function createArray<T = number>(): T | null {
  let t: T | null = null;
  return t;
}
let result2 = createArray();// 不穿类型给 T,T 是默认类型 number, 所以 result2 是 number 类型
let result3 = createArray<string>(); // 传了 string,上面的 T 就是string,所以 result2 是 string 类型

7 泛型的约束

在函数中使用泛型的时候,由于预先并不知道具体的类型,所以不能访问相应的类型的方法

function logger<T>(val: T) {
  console.log(val.length); //报错:val 的类型不确定,所以不能直接反问 val.length(val可能是数字类型,就不会有length属性)
}
// 解决办法:
// 1. 泛型 继承一个 接口
interface LengthWise {
  length: number
}
function logger2<T extends LengthWise>(val: T) {
  console.log(val.length); 
}
logger2("ruhua")
// 2. 泛型 继承一个 类
function logger3<T extends string>(val: T) {
  console.log(val.length); 
}
logger3("ruhua")

8 泛型 和 接口的混合使用练习

interface Cart<T> {
  list: T[]
}
let cart: Cart<string> = {
  list: ["1", "2", "3"]
}

9 泛型类型别名

  • 泛型类型别名可以表达更复杂的类型
type Cart2<T> = { list: T[] } | T[];
let c1: Cart2<string> = { list: ["1"] }
let c2: Cart2<string> = ["1"]

10 泛型接口 VS 泛型类型别名

  • 接口创建了一个新的名字,它可以在其他任意地方被调用。而类型别名并不创建新的名字,例如报错信息就不会使用别名
  • 类型别名不能被 extends(继承) 和 implements(实现),这时我们应该尽量使用接口代替类型别名
  • 当我们需要使用联合类型或者元组类型的时候,类型别名会更合适

interface 定义一个实实在在的接口,它是一个真正的类型。 type 一般用来定义别名,并不是一个真正的类型

posted @   真的想不出来  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示