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

# 引入

下面创建一个函数, 实现功能: 根据指定的数量 count 和数据 value , 创建一个包含 countvalue 的数组 不用泛型的话,这个函数可能是下面这样:

function createArray(value: any, count: number): any[] {
  const arr: any[] = [];
  for (let index = 0; index < count; index++) {
    arr.push(value);
  }
  return arr;
}

const arr1 = createArray(11, 3);
const arr2 = createArray("aa", 3);
console.log(arr1[0].toFixed(), arr2[0].split(""));
1
2
3
4
5
6
7
8
9
10
11

# 使用函数泛型

function createArray2<T>(value: T, count: number) {
  const arr: Array<T> = [];
  for (let index = 0; index < count; index++) {
    arr.push(value);
  }
  return arr;
}
const arr3 = createArray2<number>(11, 3);
console.log(arr3[0].toFixed());
// console.log(arr3[0].split('')) // error
const arr4 = createArray2<string>("aa", 3);
console.log(arr4[0].split(""));
// console.log(arr4[0].toFixed()) // error
1
2
3
4
5
6
7
8
9
10
11
12
13

# 多个泛型参数的函数

一个函数可以定义多个泛型参数

function swap<K, V>(a: K, b: V): [K, V] {
  return [a, b];
}
const result = swap<string, number>("abc", 123);
console.log(result[0].length, result[1].toFixed());
1
2
3
4
5

# 泛型接口

在定义接口时, 为接口中的属性或方法定义泛型类型
在使用接口时, 再指定具体的泛型类型

interface IbaseCRUD<T> {
  data: T[];
  add: (t: T) => void;
  getById: (id: number) => T;
}

class User {
  id?: number; //id主键自增
  name: string; //姓名
  age: number; //年龄

  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

class UserCRUD implements IbaseCRUD<User> {
  data: User[] = [];

  add(user: User): void {
    user = { ...user, id: Date.now() };
    this.data.push(user);
    console.log("保存user", user.id);
  }

  getById(id: number): User {
    return this.data.find((item) => item.id === id);
  }
}

const userCRUD = new UserCRUD();
userCRUD.add(new User("tom", 12));
userCRUD.add(new User("tom2", 13));
console.log(userCRUD.data);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 泛型类

在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型

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;
};

let myGenericString = new GenericNumber<string>();
myGenericString.zeroValue = "abc";
myGenericString.add = function(x, y) {
  return x + y;
};

console.log(myGenericString.add(myGenericString.zeroValue, "test"));
console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 泛型约束

如果我们直接对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性

// 没有泛型约束
function fn<T>(x: T): void {
  // console.log(x.length)  // error
}
1
2
3
4

我们可以使用泛型约束来实现

interface Lengthwise {
  length: number;
}

// 指定泛型约束
function fn2<T extends Lengthwise>(x: T): void {
  console.log(x.length);
}
1
2
3
4
5
6
7
8

我们需要传入符合约束类型的值,必须包含必须 length 属性:

fn2("abc");
// fn2(123) // error  number没有length属性
1
2