前端的程序员可能对泛型不是很了解,了解Java这种强类型语言可能会知道泛型,使用泛型可以编写动态可重用的TS代码,在TS中泛型一般用于类、接口和函数。
今天我们就来学习在TypeScript中如何去使用泛型,以及一般会用到泛型的场景。
1. 快速理解泛型
可能很多熟悉JS开发的前端搞不懂泛型是啥,下面我们通过一个最简单的例子来明白泛型。
这两个功能相同但只是入参和返回的类型不同,如果在TS中不使用泛型的话,就要定义两个函数,只是它的类型不同。
// 数字类型
function fun(args: number): number {
return args;
}
// 字符串类型
function fun(args: string): string {
return args;
}
当然你可以说用any
类型啊
function fun(args: any): any {
return args;
}
但使用any
其实是逃避类型检查,和使用JS一样,那还用TS干嘛。
下面我们使用泛型来实现
2. 使用泛型
要创建一个泛型,需要使用Type
参数,类型参数一般用T或<T>定义,表示类、接口或者函数的数据类型。
下面我们用泛型改写上面的函数
function fun<T>(args:T):T {
return args;
}
使用泛型函数也很简单
let result = fun<string>("Hello World");
或者这样
let result2 = fun<number>(200);
我们可以去跑一下代码验证一下,可以去官方的playground
地址:https://www.typescriptlang.org/play
以上是泛型在TS中最简单用法,平时也挺常用的。
下面来看看稍微复杂点的泛型用法
3. 多种类型的泛型
上面我们使用T
来表示一个类型,那么如果一个函数有很多参数,我们可以用不同的字母来表示类型。比如下面这样
function fun<T, U, V>(args1:T, args2: U, args3: V): V {
return args3;
}
上面的函数接收args1、args2、args3共3个参数,并返回args3。这些参数不限定类型,因为T, U, V被用作函数参数的泛型类型。
下面调用这个函数
let result3 = fun<string, number, boolean>('小帅', 23, false);
然后我们运行一个试试
函数返回第三个参数,所以是false
泛型不光可以用于函数,也可以用于类和接口,下面我们来继续看
4. 创建泛型类
和函数差不多,类的泛型也使用<>
中的类型参数,然后在整个类中使用<T>类型来定义方法和属性。
我们来创建一个自定义数组的类,定义一个arr
数组属性,数组的类型为一个泛型
class customArray<T> {
private arr: T[] = [];
}
创建一个获取该数组的方法
getItems (): T[] {
return this.arr;
}
再来创建一个addItem
方法,用来向数组中push元素
addItem(item: T) {
this.arr.push(item);
}
arr数组的类型为T[]
,所以我们的数组可以为任意类型,可以是数字、字符串、布尔等任意类型。
接着在添加一个removeItem方法,用于删除数组的指定元素
removeItem(item: T) {
let index = this.arr.indexOf(item);
if(index > -1) {
this.arr.splice(index, 1);
}
}
现在类的属性和方法写的差不多了,我们来测试一下结果如何
let numObj = new customArray<number>();
numObj.addItem(10);
let strObj = new customArray<string>();
strObj.addItem('小帅');
console.log(numObj);
console.log(strObj);
console.log(numObj.getItems());
console.log(strObj.getItems());
我们创建了一个数字类型的numObj
对象,一个字符串类型的strObj
对象
下面我们来了解关于泛型的一些约束力
5. 泛型的约束
上面我们学会了怎么给函数和类去使用泛型作为类型,但使用泛型也有一些缺点,比如下面的例子
function getLength<T>(args: T) : number {
return args.length;
}
在上面的函数中,如果我们传入的参数有length
属性会正常工作,如果没有就会报错
可以看到错误为泛型T
并没有length属性,那我们怎么办呢
我们可以用一个通用的约束,创建一个名为 funcArgs 的接口并定义length属性
interface funcArgs {
length: number;
}
现在我们来修改一下
function getLength<T extends funcArgs>(args:T) : number {
return args.length;
}
下面我们来跑一下
可以看到,使用没有length
参数的类型,TS就会抛出异常。
如果参数具有length属性,就不会有任何错误消息。
总结
今天我们学习了如何在TypeScript中使用泛型,包括在函数、类、接口应用泛型等。
如果本文有帮助,微信搜索【小帅的编程笔记】,每天一个小知识