一、定义
比如我们有一个函数,如果不使用范型是这样的
function getData(arg: number): number {
return arg;
}
它只能传入number类型,如果我们要传入一个string类型的是编译不通过的,所以我们可以写另一个函数或者用any类型
function getData1(arg: string): string {
return arg;
}
function getData2(arg: any): any {
return arg;
}
那么问题来了,如果重新写那么我们就不能做到复用了,如果用any就不能保证传进去的类型和传出来的类型统一,所以我们有了范型
function getData(arg: T): T {
return arg;
}
getData(123)
getData(123)
getData(false)//利用了类型推论,编译器会根据传入的参数自动地帮助我们确定T的类型
T:表示范型,具体什么类型是调用的这个方法的时候决定的(注意:T也可以是任意其他字母)
所以范型可以支持不确定的数据类型,传入的参数和返回值的类型一致。
二、范型变量
如果我们想打印一个数组的长度
function getLength(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
如果这么做,编译器会报错说我们使用了arg的.length属性,但是没有地方指明arg具有这个属性。 记住,这些类型变量代表的是任意类型,所以使用这个函数的人可能传入的是个数字,而数字是没有.length属性的。
现在假设我们想操作T类型的数组而不直接是T。由于我们操作的是数组,所以.length属性是应该存在的。 我们可以像创建其它数组一样创建这个数组:
function getLength(arg: T[]): T[] {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
三、范型类
泛型类使用(<>)括起泛型类型,跟在类名后面。
class Minclass {
public list: T[] = []
add(value: T):void {
this.list.push(value)
}
min():T{
let minNum = this.list[0]
for(let i =0; i < this.list.length; i++){
if(minNum > this.list[i]){
minNum = this.list[i]
}
}
return minNum
}
}
let m = new Minclass()
m.add(2)
m.add(6)
m.min() //2
let s = new Minclass()
s.add('m')
s.add('c')
s.min()//c
四、范型接口
interface ConfigFn{
(value:T):T
}
let getData:ConfigFn = function(value:T):T{
return value
}
通用范型接口:
function getData(value:T):T{
return value
}
interface ConfigFn{
(value:T):T
}
let getData:ConfigFn = getData
let getData1:ConfigFn = getData
五、在泛型约束中使用类型参数
class User{
username: string
password: string
}
class Mysql{
add (user:User):boolean{
console.log(user)
return true
}
}
let u = new User()
u.username = '张三'
u.password = '123'
let m = new Mysql()
m.add(u)
我们可以通过范型约束来更好的实现上面的代码
class Mysql{
add(info:T):boolean{
console.log(Info)
return true
}
}
let u = new User()
u.username = '张三'
u.password = '123'
let my = new Mysql()
my.add(u)