# TypeScript 泛型

发布时间 2023-12-26 17:40:06作者: 我是ed

TypeScript 泛型

参考资料:https://ts.xcatliu.com/advanced/generics.html

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

案例

定义一个函数,传入两个参数,第一个参数是数据,第二个参数是数量。
函数的作用是根据数量,产生对应个数的数据,存放在一个数组中。
即:( "我是ed." , 3 ) => [ "我是ed." , "我是ed." , "我是ed." ]

OK ,开始编写代码,首先我们确定数量一定是 number 类型,但是数据不一定是什么类型,所以我们先假设传进来的是 number 类型:

/**
 * 定义一个函数,传入两个参数,第一个参数是数据,第二个参数是数量。
 * 函数的作用是根据数量,产生对应个数的数据,存放在一个数组中。
 * 即:`( "我是ed." , 3 )   =>  [ "我是ed." , "我是ed." , "我是ed." ]`
 */

// 假设传进来的value是数字
function getArr(value: number, count: number): number[] {
  const arr: number[] = [];
  for (let i = 0; i < count; i++) {
    arr.push(value);
  }
  return arr
}
console.log(getArr(123, 3))

ok,如果是数字的话,没问题,我们编译执行一下看结果:

在这里插入图片描述

OK,没有一点儿问题。

接下来,如果 value 传入的是字符串怎么办?首先一点,原则上不推荐使用 any,可以使用泛型,在定义的时候不需要确定类型,而是使用的时候在确定。

// T 表示任意输入的类型
function getArr<T>(value: T, count: number): T[] {
  const arr: T[] = [];
  for (let i = 0; i < count; i++) {
    arr.push(value);
  }
  return arr
}
// 原则上不推荐使用 any
// 可以使用泛型,在定义的时候不需要确定类型,而是使用的时候在确定
console.log(getArr("我是ed.", 3))

然后我们同样编译执行一下:

在这里插入图片描述

完美!奈斯!成功解决问题!而且我们把鼠标移上去之后,发现 ts 已经帮我们做了类型推论:

在这里插入图片描述

如果我们确认返回类型的话,我们也可以提前定义返回类型:

console.log(getArr<string>("我是ed.", 3))
console.log(getArr<number>(25, 5))

如果没有确定类型的话,就会走类型推断,它会自动推断返回的类型。

注意,泛型使用的 T 不是绝对的,可以修改成别的内容,但是默认都写作 T

多个类型参数

定义泛型的时候,可以一次定义多个类型参数。

假设我们现在有一个元组有两个元素,元素类型不确定,我们经过一个函数的处理,将两个元素调个儿返回。
即:[ "我是ed." , 25 ] => [ 25 , "我是ed." ]

直接编写代码吧:

function updateArr<T, U>(t: [T, U]): [U, T]{
  return [t[1], t[0]]
}
console.log(updateArr(["我是ed.", 25]))
console.log(updateArr([true, 145]))

看一下编译后的执行结果:

在这里插入图片描述

没有问题,我们鼠标移入看一下,ts 也已经为我们做了类型推断:

在这里插入图片描述

泛型约束

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

// 获取参数的长度
// 使用泛型约束,约束这个任意输入的类型,必须要有length属性
interface ILength{
  length: number
}
// 通过接口约束泛型
function getLength<T extends ILength>(x:T) :number {
  return x.length
}
console.log(getLength(123)) // 报错

通过接口,对泛型进行了约束,T extends ILength 的意思可以理解为,我不知道传入的是什么类型,但是她受到了接口约束,要求传入的参数必须包含 length 属性,如果没有,就不行,getLength(123) ,很明显传入的 123 数字没有 length 属性,所以会报错!

在这里插入图片描述

泛型接口

可以使用含有泛型的接口来定义函数的形状。

// 先定义一个泛型接口
interface IArr {
  <T>(value: T, count: number): Array<T>
}
// T 表示任意输入的类型
let getArr1: IArr = function getArr<T>(value: T, count: number): T[] {
  const arr: T[] = [];
  for (let i = 0; i < count; i++) {
    arr.push(value);
  }
  return arr
}
// 使用
console.log(getArr1("123", 3))

泛型类

与泛型接口类似,泛型也可以用于类的类型定义中。

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };