TS从入门到精通(七) 泛型

103 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

泛型

  • 把运行时期的问题提到编译时期

  • 在函数重载中,同一个函数参数类型是会不一样的。这种情况下就比较适合使用泛型。 在保证类型安全的前提下,让函数与多种类型一起工作实现复用

  • 语法为函数名字后面跟一个<参数名> 参数名可以随便写 一般都是使用 T U K等

  • 等于是像函数参数一样写了一个any类型的形参便可以接收任意类型的参数

    play<T>(name:T){
        console.log(typeof name)
    }
    play(111) //number
    play("TiGa")//string

泛型约束

  • 泛型在某些时候也没有那么好用,例如泛型接收一个字符串你想获得length属性这时候你会发现你无法拿到length属性并且报编译错误以及运行错误
    //这种时候如果第一时间想到类型断言,说明学的不错,但是我们要说的是第二种方式
    //通过对泛型进行约束,使泛型具备length属性
    interface A {
      length: number
    }
    function getlength<T extends A>(arr: T) {
      console.log(arr.length);
    }

    getlength("dddd")
  • 注意不要搞混,泛型约束只能通过extends关键字来实现接口
  • 但是类上必须使用interface实现接口

使用keyof 关键字约束对象

  • keyof 映射出一个联合类型
  • keyof 关键字接收一个对象类型 生成其键名称的联合类型(对象中的所有键名)
    //K 继承了T类型的联合类型 约束了范围
    function prop<T, K extends keyof T>(obj: T, key: K) {
       return obj[key]
    }
    let obj = { a: 1, b: 2, c: 3 }
    prop(obj, 'a') 
    prop(obj, 'd') //此时就会报错,因为继承的联合类型中不存在d

泛型类

  • 在类后加上<类型> 这个类就变成了一个泛型类,需要在使用的时候传递类型过来
  • 传递过来的类型在类中都可以用
    class MyList<T> {
        private lists: T[] = new Array();
        public add( e:T):void {
            this.lists.push(e);
        }
        public remove(e:T):void {
            let index=this.lists.indexOf(e)
            this.lists.splice(index,1);
        }
    }
    let m1=new MyList<number>();
    m1.add(1)
    m1.add(2)
    m1.add(3)
    m1.add(4)
    m1.add(5)
    m1.remove(5)
    console.log(m1);  //[1,2,3,4]

泛型方法

与上面的基本类似

  • 定义方法的同时加入泛型这个方法就是泛型方法
    play<T>(name:T){
        console.log(typeof name)
    }
    play(111) //number
    play("TiGa")//string

泛型接口

  • 需要指定类型
  • 类型变量所有成员可见
    interface Space<T>{
        id:(value:T)=>T
        ids:()=>T[]
    }
    let obj:Space<number>={
        id(value){return value},
        ids(){ return [1,2,3,4]}
    }
    obj.id(1)//1
    obj.ids()//[1,2,3,4]

总结

使用泛型可以是我们写出来的 代码更加精简更加优雅,一定要经常用。这样才能快速掌握泛型的使用。有什么不足的地方欢迎指正。