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


    为什么要使用泛型

    1. function fn(arr, n: number) {
    2. return arr
    3. }

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

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

    1. function fn(arr: any[], n: number):any[] {
    2. return arr
    3. }

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

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

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

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

    什么是泛型

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

    如何使用或书写泛型

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

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

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

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

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

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

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

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

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

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

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

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

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

    总结在函数中使用泛型

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

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

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

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

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

    • 类型别名

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

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

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

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

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

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

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

    1. class arrayHelper{
    2. handle1(arr:T[]):T[]{}
    3. handle2(arr:T[]):T[]{}
    4. }

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

    1. class arrayHelper{
    2. constructor(private arr:T[]) {
    3. }
    4. handle1(n:number){
    5. //使用arr的时候就用this.arr就行了
    6. let newArr:T[]=this.arr
    7. }
    8. handle2(){
    9. let newArr:T[]=this.arr
    10. }
    11. }

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

  • 相关阅读:
    云安全是什么样子的?一文给你全说明白!
    【力扣】1106. 解析布尔表达式(C++/Go 栈的应用)
    HTML小游戏7 —— 《罗斯魔影》魔法消除游戏(附完整源码)
    java中几种对象存储(文件存储)中间件的介绍
    设计模式 --- 适配器模式 Adapter Pattern
    2520. 统计能整除数字的位数 : 简单模拟题(时空复杂度最优解)
    【仿写spring之ioc篇】一、预期目标以及项目结构介绍
    NLP Step by Step -- How to use pipeline
    Nodejs+vue体育用品商城商品购物推荐系统_t81xg
    CentOS系统上定时备份与清理Java项目日志文件
  • 原文地址:https://blog.csdn.net/weixin_41277748/article/details/126514221