最近一直使用TS开发React应用,一开始对里面的<>很茫然,后来弄清楚了这是泛型,慢慢了解了它的用处后,感觉到它们是非常有用的特性。今天就来谈谈TS里的泛型的应用。
这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战
什么是泛型
首先,有必要搞清楚什么是泛型?
有人表示:Generics are to Types, what Types are to Variables
泛型对于类型的意义,正如类型对于变量的意义一样。
类型是用来描述变量代表的数据的细节,而泛型则用来代表类型的细节。
如果感觉有点抽象,你仔细琢磨琢磨就明白了
泛型的一个简单示例
我们先来看一个简单的例子:
function receiveAndPrint(arg){
console.log(arg)
return arg;
}
//上面的代码在ts里被默认添加any类型,如下:
function receiveAndPrint(arg:any):any{
console.log(arg)
return arg;
}
上面的函数接收一个参数,打印并将其返回,参数和返回值永远是any类型,这样就体验不到ts的类型检查带来的优越性了,怎么办?我们可以用泛型来描述我们的类型
function receiveAndPrint<T>(arg:T):T{
console.log(arg)
return arg;
}
//调用
receiveAndPrint<number>(123);
receiveAndPrint<string>("123");
不过好像没啥变化,因为我们没有访问泛型T对应的参数arg的内容:
//下面代码会报错:Property 'length' does not exist on type 'T'.
function receiveAndPrintLen<T>(arg:T):T{
console.log(arg.length)
return arg;
}
//我们还需要给泛型T添加约束条件,我们使用接口来描述该约束
interface lengthwise {
length:number
}
function receiveAndPrintLen<T extends lengthwise>(arg:T):T{
console.log(arg.length)
return arg;
}
//此外我们还可以声明多个类型参数
function get<T, K extends keyof T>(p: T, key: K): any {
return p[key]
}
ok,我们可以看到泛型是非常有趣且有用的。
其他使用泛型的地方
接口里使用泛型
除了函数,我们还可以在类型或者接口里使用泛型:
interface ChangeRecord<ValueType> {
oldValue: ValueType;
newValue: ValueType;
}
function isChanged<ValueType>(change: ChangeRecord<ValueType>){
return change.oldValue !== change.newValue;
}
//基于上面的接口定义,定义新的类型
//温度变化记录
type ChangeInTemperature = ChangeRecord<number>;
//传体桖的变化记录
type ChangeWearTShirt = ChangeRecord<boolean>;
有时候我们想定义一个可能为空的某个类型:
type MaybeNull<ValueType> = ValueType|null;
const myGender:MaybeNull<boolean> = null;
const herGender:MaybeNull<boolean> = 1;//1 represent male
可以说,接口是一种抽象的东西,而泛型可以让接口更加抽象。
泛型类
我们还可以在类里使用泛型,让类更加通用。
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;
};