TypeScript 中的泛型

泛型的定义

泛型:软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
在像 C#和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。
通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)

只能返回 string 类型的数据

1
2
3
function getData(value: string): string {
return value;
}

同时返回 string 类型 和 number 类型 (代码冗余)

1
2
3
4
5
6
7
function getData1(value: string): string {
return value;
}

function getData2(value: number): number {
return value;
}

同时返回 string 类型 和 number 类型 any 可以解决这个问题

any 放弃了类型检查,传入什么 返回什么。比如:传入 number 类型必须返回 number 类型 传入 string 类型必须返回 string 类型

1
2
3
4
5
6
7
function getData(value: any): any {
return "哈哈哈";
}

getData(123);

getData("str");

传入的参数类型和返回的参数类型可以不一致

1
2
3
function getData(value: any): any {
return "哈哈哈";
}

泛型函数

可以支持不特定的数据类型 要求:传入的参数和返回的参数一直

T 表示泛型,具体什么类型是调用这个方法的时候决定的

基础用法

1
2
3
4
5
6
7
8
function getData<T>(value: T): T {
return value;
}
getData<number>(123);

getData<string>("1214231");

getData<number>("2112"); /*错误的写法*/
1
2
3
4
5
6
7
function getData<T>(value: T): any {
return "2145214214";
}

getData<number>(123); //参数必须是number

getData<string>("这是一个泛型");
1
2
3
4
5
function join<T>(first: T, second: T) {
return `${first} ${second}`;
}
join<number>(1, 2);
join<string>("a", "b");

多个泛型的定义

1
2
3
4
5
6
function joinMul<T, P>(first: T, second: P) {
return `${first} ${second}`;
}
joinMul<string, number>("a", 2);
// 泛型的类型推断
joinMul("a", 2); // function joinMul<string, number>(first: string, second: number): string

泛型中数组的使用

1
2
3
4
5
6
function arrFun<T>(params: Array<T>) {
return params;
}

arrFun<number>([1, 2]);
arrFun<string>(["a", "b"]);

泛型类

基础用法

例:比如有个最小堆算法,需要同时支持返回数字和字符串 a - z 两种类型。 通过类的泛型来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MinClass {
public list: number[] = [];
add(num: number) {
this.list.push(num);
}
min(): number {
var minNum = this.list[0];
for (var i = 0; i < this.list.length; i++) {
if (minNum > this.list[i]) {
minNum = this.list[i];
}
}
return minNum;
}
}

var m = new MinClass();

m.add(3);
m.add(22);
m.add(23);

alert(m.min());

类的泛型

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
class MinClas<T> {
public list: T[] = [];

add(value: T): void {
this.list.push(value);
}

min(): T {
var minNum = this.list[0];
for (var i = 0; i < this.list.length; i++) {
if (minNum > this.list[i]) {
minNum = this.list[i];
}
}
return minNum;
}
}

var m1 = new MinClas<number>(); /*实例化类 并且制定了类的T代表的类型是number*/
m1.add(11);
m1.add(3);
m1.add(2);
alert(m1.min());

var m2 = new MinClas<string>(); /*实例化类 并且制定了类的T代表的类型是string*/

m2.add("c");
m2.add("a");
m2.add("v");
alert(m2.min());

例:获取用户身份

1
2
3
4
5
6
7
8
9
class Id<T> {
constructor(private people: T[]) {}
getId(index: number): T {
return this.people[index];
}
}

const userId = new Id<string>(["教师", "学生", "医生"]);
console.log(userId.getId(0)); // 教师

泛型中的继承

interface 接口定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface IdModel {
name: string;
}

class IdExtends<T extends IdModel> {
constructor(private people: T[]) {}
getId(index: number): string {
return this.people[index].name;
}
}

const userIdExtends = new IdExtends<IdModel>([
{ name: "教师" },
{ name: "学生" },
{ name: "医生" }
]);

console.log(userIdExtends.getId(1)); // 学生

泛型类型约束

1
2
3
4
5
6
7
8
9
class GenConstraint<T extends number | string> {
constructor(private people: T[]) {}
getId(index: number): T {
return this.people[index];
}
}

const userGenConstraint = new GenConstraint<string>(["教师", "学生", "医生"]);
console.log(userId.getId(2)); // 医生

泛型接口

1
2
3
4
5
6
7
8
9
10
11
interface ConfigFn {
<T>(value: T): T;
}

var getData: ConfigFn = function <T>(value: T): T {
return value;
};

// getData<string>('张三');

// getData<string>(1243); //错误
1
2
3
4
5
6
7
8
9
10
11
12
13
interface ConfigFn<T> {
(value: T): T;
}

function getData<T>(value: T): T {
return value;
}

var myGetData: ConfigFn<string> = getData;

myGetData("20"); /*正确*/

// myGetData(20) //错误