TS学习(九) :TS中的泛型

为什么要使用泛型

function fn(arr, n: number) {
    return arr
}

在上面函数中第一个参数是个数组,第二个参数我们可以确定是个number类型的数字,但是第一个参数我们无法断定

它是number[]的数组,还是string[]的数组,它可以是任何类型的数组,既然是任何类型那我们是不是可以写成any[]类型

function fn(arr: any[], n: number):any[] {
    return arr
}

函数的参数,返回值都是any[]类型的数组,当我们给函数传入一个string[]类型的数组,

const newArr = fn(['1', '2', '3', '4', '5', '6'], 3)

按理来说,在函数里面因该能识别出函数的参数类型,函数的返回值类型都是string[]类型,结果显而易见无法识别,

所以这里使用any类型是不行的,所以这个时候我们就得使用泛型来解决这个问题。总的来说,有时,书写某个函数时,会丢失一些类型信息(多个位置的类型应该保持一致或有关联的信息)

什么是泛型

泛型是指附属于函数、类、接口、类型别名之上的类型,当某个函数的参数,返回值和内部使用时的类型无法确定的情况下,就可以使用泛型来进行约束

如何使用或书写泛型

在函数名之后写上fn<泛型名>,通常泛型名使用大写的T,当然你可以随意命名,在调用的时候函数名字后面加上fn<泛型类型>

function fn<T>(arr:any[], n: number):any[] {}
fn<number>(['1','2','3'],2)

泛型类型“T”就像一个参数,可供传递,如我们在调用函数时在尖括号中传入,则这个T(泛型)的类型就是number,

这样我们就可以any类型都换成泛型就可以了,这样就当泛型参数传入number类型时,函数的返回值就是number类型的数组

function fn<T>(arr:T[], n: number) :T[]{
    const newArr: T[] = [];
    return newArr
}
const newArr = fn<number>([1, 2, 3, 4, 5, 6], 3)

这里 T类型就是number,TS就会识别类型,当然你也可以不传入泛型类型,如下

function fn<T>(arr:T[], n: number) :T[]{
    if (n >= arr.length) {
        return arr
    }
    const newArr: T[] = [];
    for (let i = 0; i < n; i++) {
        newArr.push(arr[i])
    }
    return newArr
}
const newArr = fn([1, 2, 3, 4, 5, 6], 3)

这时TS会自动识别[1, 2, 3, 4, 5, 6]函数第一个参数你传入的是一个number[]类型的数组,fn<T>(arr:T[], n: number) :T[]{

从而推导出arr:T[]中的T泛型是number类型,这样其他几个T泛型也都是number,这样最终的返回结果newArr也是number[]类型的数组

说到这里不知道大家有没有疑问,当如果我不传递T泛型参数时,我的数组是长这样的[1, 2, '4', 5],那它返回的是什么类型?

是any吗?还是说还是一个数组,只不过是里面既有number又有string类型的数组,当然是第二种的只不过这个时候表示的是(string | number)[]的写法

function fn<T>(arr:T[], n: number) :T[]{
    if (n >= arr.length) {
        return arr
    }
    const newArr: T[] = [];
    for (let i = 0; i < n; i++) {
        newArr.push(arr[i])
    }
    return newArr
}

const newArr = fn([1, 2, '4', 5, 5, 6], 3)

当然这种是在你不传递Tf泛型参数的情况下才能这样的,如果又泛型参数,就只能规规矩矩的进行了

总结在函数中使用泛型

泛型相当于是一个类型变量,在定义时,无法预先知道具体的类型,可以使用该变量来代替,只有到调用时,才能确定它的类型

很多时候,TS会只能的根据传递参数,推导泛型的具体类型,如果无法推导,并且又没有传递具体的类型,则会返回空对象的类型

当然泛型也可以设置默认值,当没有传递时就使用默认值,就像js中函数中的参数一样设置默认值

在类型别名、接口、类型中使用泛型

直接在名称后面写上<泛型名称>

  • 类型别名

例子: 回调函数:判断数组中的某一项是否满足条件

type callback= (n:number,i:number)=>boolean;

该类型只能传number类型的数组,这就有弊端,我不一定数组就是number类型的,不确定类型,

type callback<T>= (n:T,i:number)=>boolean;

这个时候就可以使用泛型了,只要传入类型泛型类型T,n的类型也是T,这样就可以根据传入的类型就可以了

  • 接口:这个和类型别名类似 例子如下
interface callback<T>{(n:T,i:number):boolean;}
//类似js数组中的filter方法
function filter<T>(arr: T[], callback: callback<T>): T[] {
    const newArr: T[] = [];
    arr.forEach((n,i)=>{
        if(callback(n,i)){
            newArr.push(n);
        }
    })
    return newArr
}

先看例子,这样写handle1和handle2的泛型没有任何联系,在调用的时候传什么就是什么

class arrayHelper{
    handle1<T>(arr:T[]):T[]{}
    handle2<T>(arr:T[]):T[]{}
}

这样写就没啥意思,我们想能只要传一个就代表所有,如下

class arrayHelper<T>{
    constructor(private arr:T[]) {
    }
    handle1(n:number){
        //使用arr的时候就用this.arr就行了
        let newArr:T[]=this.arr
    }
    handle2(){
        let newArr:T[]=this.arr
    }
}

这样就不用在每次调用函数的时候去传入泛型,而是在创建类型时去传入,这样就可以整个类都是该类型

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值