写在前面
泛型是ts中比较难懂和难掌握的概念,一来是因为从js拥抱ts还是需要理解成本,二来是如果不能充分理解泛型那么遇到适合泛型的应用场景也不会想到拔出此利剑,不理解+很少用,一来二去就成为了埋藏在ts中的秘宝了。
泛型是什么
官方解释:泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。光看定义可能很抽象,先来看看代码吧
// js实现的返回参数长度的数组
function returnParamsAdd(a) {
return new Array(+a).fill(a)
}
用上ts自然要严谨些,需要返回数字类型的参数长度的数组
function returnParamsArr(a: number): number[] {
return new Array(+a).fill(a)
}
好像问题不大,那么需求来了,返回字符类型的参数长度的数组
function returnParamsArr(a: string): string[] {
return new Array(+a).fill(a)
}
聪明的小伙伴看出来了,明明逻辑都是一样的,能不能用一种更通用的方法去描述returnParamsAdd呢?没错,这时候该把泛型请出来了。“预先指定具体的类型,而在使用的时候再指定类型”这就是泛型的好处。来试试用函数泛型改造一下吧。
function returnParamsArr<T extends string | number>(a: T):Array<T> {
return new Array(+a).fill(a);
}
如此一来,用泛型可以更灵活的处理
const stringArr = returnParamsArr<string>('3');
console.log(stringArr) // ['3', '3', '3'];
const numberArr = returnParamsArr<number>(3);
console.log(numberArr) // [3, 3, 3];
所以简单来说,泛型就是预先设置好类型占位符,等使用函数/类/接口的时候再指定确定的类型。
函数泛型及使用
function returnParamsArr<T>(a: T):Array<T> {
return new Array(10).fill(a);
}
returnParamsArr<boolean>(true)
类泛型及使用
class AddClass<T> {
parmas: T;
add: (x: T, y: T) => T;
}
let addNumber = new AddClass<number>();
addNumber.parmas = 0;
addNumber.add = function(x, y) { return x + y; };
接口泛型及使用
interface Add<T> {
parmas: T;
add: (x: T, y: T) => T;
}
const addNumber: Add<number> = {
parmas: 0,
add: (x, y) => x + y
}
addNumber.parmas = 0;
addNumber.add(2, 3);
多类型参数
function returnParamsArr<T, U>(a: T, b:U):[U, T] {
return [b, a];
}
class AddClass<T, U> {
parmas: U;
add: (x: T, y: U) => [U, T];
}
interface Add<T, U> {
parmas: U;
add: (x: T, y: U) => [U, T];
}
有些情况我们需要限定泛型参数的类型,可以用extends关键字,用以下代码举例子:
// T只能是字符或者数字类型
function returnParamsArr<T extends string | number>(a: T):Array<T> {
return new Array(+a).fill(a);
}
总结
泛型是TS的重要一环,适合解决一些因为不同类型但是业务逻辑相似的场景,理解泛型容易,如何能在业务中找到适用场景加以运用优化不容易,这需要开发者自身长期的实践经验。