感受TS里泛型的好处

1,608 阅读1分钟

最近一直使用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; 
};