泛型:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持
实现方法:function method<T>(value:T):T{} 这个T只是用法最多的,但不是写死的,你想用A,B什么来代替也一样
为什么说解决复用性?大家想一下,如果我们要定义一个方法,但是要约束传入的参数和返回的类型一致,也就是说,我传入参数1,要返回number类型,传入‘张三’,要返回string类型,那么现在是不是要写两个方法分别来约束,这就造成了冗余,为了解决这个问题,我们可以使用泛型来定义约束
1、泛型函数
//旧方法约束传参和返回类型保持一致
function getData(value:number):Number{
return value
}
function getData_c(value:string):string{
return value
}
//泛型解决传参和返回类型一致
function getData<T>(value:T):T{
return value
}
console.log(getData<number>(123)) //<number>传入number 那么value必须为number 传入string时就会报错
console.log(getData<string>('123'))
2、泛型类
实现一个类 来找到数组中的最小值,数组元素类型不定
class minCount{
public list:number[]=[];
add(value:number):void{
this.list.push(value)
}
min():number{
let minNum=this.list[0]
for(var i=0;i<this.list.length;i++){
if(this.list[i]<minNum){
minNum=this.list[i]
}
}
return minNum
}
}
var a=new minCount()
a.add(1)
a.add(2)
a.add(3)
alert(a.min())
这种方法弊端:辛辛苦苦写了一个类,最终只能比较数字类型,要是想比较字符串类型还要重构,这也太麻烦了,下面看改造成泛型的类
class minCount<T>{
public list:T[]=[]
add(value:T){
this.list.push(value)
}
min():T{
let minNum=this.list[0]
for(var i=0;i<this.list.length;i++){
if(this.list[i]<minNum){
minNum=this.list[i]
}
}
return minNum
}
}
var a=new minCount<number>()
a.add(1)
a.add(2)
a.add(3)
// a.add('1') //错误 不能赋值给number类型
var b=new minCount<string>()
b.add('a')
b.add('b')
b.add('c')
看下泛型都是用在哪些地方
1、类的后边
2、数组类型
3、add方法的传参
4、min方法的返回值
这四处既能够很好的保证你传入的参数和返回参数一致,又能降低冗余,起到了限制的作用和不确定数据类型的约束
3、泛型接口
interface config{
<T>(value:T):T;
}
var getYear:config=function<T>(value:T):T{
return value
}
var c=getYear<string>('张三') //正确
// var c=getYear<number>('张三') //错误
4、类作为参数约束传入数据的类型
这个举例子来说可能更明了一些:假设你想定义一个方法,这个方法是往数据库传入数据的,但是你要做一个约束,不能让非法类型的数据传入数据库。
比如定义一个用户类,要求传入用户名和密码,这时候如果传入的是性别或者其他属性,肯定是不行的。这时候就要用到类作为参数来约束传入数据的类型,可以理解为接口的特性,就是起到约束的作用。
然后你还有一个文章类,你要传入title,desc,type等属性,这时候如果传入的参数是年龄,大小这些属性肯定也是不行的,这时候你就要用到文章类来约束传入的参数。下面看具体的例子
class User{
username:string | undefined;
password:string | undefined;
}
class Artical{
title:string | undefined;
desc:string | undefined;
type:string | undefined
}
class mysqlDB{
//定义一个方法 传入的参数要遵从User类
add(value:User):boolean{
console.log(value)
return true
}
}
//这样定义的类如果想要约束多个类的规范 就必须重复的写多个 这时候使用泛型 就可以避免重复了
class mysqlDB_c{
//定义一个方法 传入的参数要遵从User类
add(value:Artical):boolean{
console.log(value)
return true
}
}
var u=new User()
// u.username='张三'
u.password='123445'
var params={
name:'09'
}
var DB=new mysqlDB()
var DB_C=new mysqlDB_C()
// DB.add(params) //错误 这里的params不符合user类的规范
// DB.add(u)
var artical=new Artical()
artical.title='学习'
artical.desc='学习让人进步'
DB_C.add(artical)
这样虽然可以实现约束效果,但是如果还有更多的类约束,那么岂不是要写很多的mysqlDB类,这样显然不可行,下面看使用泛型来解决这个问题。
class User{
username:string | undefined;
password:string | undefined;
}
class Artical{
title:string | undefined;
desc:string | undefined;
type:string | undefined;
constructor(params:{ //这里再次进行传入参数约束 必须穿入title,desc type 可不传
title:string | undefined;
desc:string | undefined;
type?:string | undefined;
}){
this.title=params.title,
this.desc=params.desc,
this.type=params.type
}
}
//这样定义一个泛型类 在实例化的时候可以传入约束类 避免了重复构造mysqlDB类
class mysqlDB<T>{
add(value:T):boolean{
console.log(value)
return true
}
update(value:T,id:number):boolean{
console.log(value,id)
return true
}
}
var u=new User()
u.username='张三'
var a=new Artical({
title:'好好学习',
desc:'天天向上'
})
var db=new mysqlDB<User>()
db.add(u)
var db1=new mysqlDB<Artical>()
db1.add(a)
db1.update(a,12)
这里定义user类和artical类的时候有些区别,artical类直接在内部实现了constructor,这样就可以直接在实例化的时候传参,而且可以看到artical类在构造的时候也是进行了约束的,这样约束之后在传参的时候就必须传入title,desc参数,type参数是可选的
mysqlDB类在定义的时候使用了泛型的方法,<T>确保了实例化对象的时候使用了哪种类约束。使用了哪种规范就必须按照这种方式来传参了。