很多时候我们希望一个函数或者一个类可以支持多种数据类型,有很大的灵活性。
很多小伙伴可能会想到函数重载,联合类型,或者any类型等。
函数重载代码量大,联合类型冗长。
function log(value:any):any{
console.log(value);
return value;
}
虽然使用any类型可以满足我们的需求,但是缺失类型信息,这不是我们所希望的,这里我们就可以使用泛型。
泛型函数:
不预先确定的函数类型,具体的类型在使用的时候才能确定
// 泛型函数
function logs<T>(value:T):T{
console.log(value);
return value;
}
// 类型T不需要预先指定,相当于any类型 ;保证了输入参数和返回值是一致的
泛型函数有两种调用方式:
- 指明参数类型:logs<string[]>(['a','b']);
- 利用TS的类型推断,省略参数类型:logs(['c','d'])
我们不仅可以用泛型来定义一个函数,也可以定义一个函数类型
type Log=<T>(value:T)=>T;
let MyLog:Log=log;
泛型约束接口
// 这里仅仅使用泛型来约束了一个函数
interface L{
<T>(value:T):T
}
// 使用泛型来约束接口的其他成员,当泛型约束整个接口的时候,实现时我们必须指定一个类型
interface Lj<T>{j
(value:T):T
}
泛型可以理解为代表函数类型的参数。
泛型类:
//泛型约束类成员
class Logs<T>{
run(value:T){
console.log(value);
return value;
}
}
let log1=new Logs<number>(); //显示传入T的类型
log1.run(1);
let log2=new Logs(); //当不指定类型参数的时候,value的值就可以是任意的类型
log2.run('lll')
// 泛型不能应用于类的静态成员
class Logs<T>{
static run(value:T){ //报错
console.log(value);
return value;
}
}
泛型约束
function Lg<T>(value:T):T{
console.log(value);
console.log(value,value.length); //T上没有length属性
return value;
}
interface Len{
length:number
}
function L<T extends Len>(value:T):T{
console.log(value);
console.log(value,value.length); //T上没有length属性,继承了接口len的length属性
return value;
}
L([1,2]); // 参数受到泛型的约束,必须具有length属性
L(1); //类型“1”的参数不能赋给类型“Len”的参数。
泛型的好处:
-
函数和类可以轻松的支持多种类型,增强程序的扩展性
-
不必写多条函数重载,冗长的联合类型声明,增强代码的可读性
-
灵活控制类型之间的约束