美文网首页
2020-11-05Typescript(2.2)

2020-11-05Typescript(2.2)

作者: 夏天的风2020 | 来源:发表于2020-11-05 18:32 被阅读0次

    泛型 Generics---typeScript中最难的一部分

    Adding simple type annotations //给我们的变量加一些简单的类型声明,
    string类型/number类型/any类型
    
    //泛型是怎么出现的,它要解决什么的问题?
    //function echo(arg){
    //   return arg
    // }
    
    //调用
    //const result = echo(123)
    //传入数字123,返回any类型,
    //我们的变量丧失了类型,
    
    
    //这样写就没啥问题了
    function echo(arg: number): number{
       return arg
     }
    const result = echo(123)
    //但是我们可能传入其他类型,
    //我们传入和返回的没办法统一,
    
    
    泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,
    而在使用的时候再指定类型的一种特性。
    
    function echo<T>(arg: T): T{
       return arg
     }
    const str: string = 'str'
    const result = echo(123)
    //传入类型,返回的也是string
    
    //我们也可以完全不指定,这时候类型推论会帮我们做事情,
    function echo<T>(arg: T): T{
       return arg
     }
    const result = echo('str')
    //类型推论会推断,str就是string类型,自然它返回的也是一个string类型,
    
    
    
    泛型可以传入多个值,
    新需求:我们有一个 tuple元组,里面有2个值,他们的类型都是随意的,
    这时候我要返回一个新的tuple ,调换他们的位置,
    //新建一个函数
    function swap(tuple){
       return [tuple[1],tuple[0]]
     }
    //当然会丧失他们的type,
    
    //创建泛型,
    function swap<T,U>(tuple: [T,U]): [U,T]{
       return [tuple[1],tuple[0]]
     }
    const result2 = swap(['string',123])
    
    //鼠标移至result2,显示const result2: [number,string],
    //已经出现了它的类型,
    //第0项我们可以把它当作number使用,result2[0].调用number上边的方法
    //第1项我们可以把它当作string使用,result2[1].调用string上边的方法
    
    
    本节总结
    介绍了泛型的动机和它最简单的用法,
    泛型,它就像一个占位符,或者是一个变量,
    在使用的时候我们可以把定义好的类型像参数一样传入,
    然后它可以原封不断的帮我们输出,
    

    泛型 Generics---约束泛型

     //上节学习了泛型出现的动机要解决什么问题和简单用法
     //我们可以把它看成一个占位符,在使用的时候才动态的填入确定的类型值,
    
       //约束泛型
       function echoWithArr<T>(arg: T): T{
          console.log(arg.length)  //发现报错,Property 'length' does not exist on type 'T'
          return arg               //这个例子中,泛型T不一定包含属性length
        }
    
      因为在我们函数内部使用泛型变量的时候,由于事先不知道它是什么类型,
      所以不能随意的来操作它的属性和方法,
    
      //我们就决定我们这个函数应该是作用给一个含有T类型的Array,
      //这样length这个属性也就有了
    
      //T[]
      function echoWithArr<T>(arg: T[]): T[] {
          console.log(arg.length)  
          return arg              
        }
    
      //const arrs = echoWithArr([1,2,3]),
      //鼠标移至arrs,显示const arrs: number[]
    
      //但是这个解决方案不是完美的,我们只能传入数组
      //但是可能对象,甚至简单类型string都可以有length这个属性,
      //const arrs = echoWithArr('str') //会报错
    
      我们需要一个新的解决方案,我们可以对泛型进行一个约束,
      只允许函数传入那些包含length属性的变量,这就是约束泛型,
    
      interface IWithLength {
         length: number;
       }
      function echoWithLength<T extends IWithLength>(arg: T): T {
         console.log(arg.length)
         return arg
      }
      用extends关键字来约束传入的泛型,
      告诉它,你必须要有length这个属性,要不然会报错,
    
      //const str = echoWithLength('str')  //不会报错
      //鼠标移至str,显示const str:'str'
    
      //const obj = echoWithLength({length: 10})
      //鼠标移至obj,显示const obj:{length: number}
    
      //const arr2 = echoWithLength([1,2,3])
      //鼠标移至obj,显示const arr2: number[]
    
    
      //interface--Duck Typing
      只要你叫起来像鸭子,只要你有length属性,那么就可以符合这个约束,
      就没有问题,不管你是什么样的类型都可以,
      不管你是字符串,object,Array都没有问题,
    
    
      本节总结:
      着重讲了约束泛型,关键是在泛型中使用extends关键字,就可以让
      传入值满足我们特定的约束条件,而不是想传入什么就传入什么,
    

    泛型 Generics---泛型在类和接口中的使用

    //之前我们显示的泛型都是作用在函数中,在函数的参数和返回值中使用泛型,
    
    //泛型在类上边应用,
    
    我们创建一个对列类,
    队列中有两个方法,一个是进入对列push(),二是离开对列pop()
    对列是个先进先出的数据结构,所以我们使用了push()和shift()两个方法,
    这时候我们就可以使用这个对列做一些事情,
    
    class Queue {
       private data = []
       push(item){
         return this.data.push(item)
       }
       pop(item){
         return this.data.shift()
       }
     }
    
    // const queue = new Queue()  //创建一个对列
    // queue.push(1)
    //queue.push('str')
    //console.log(queue.pop().toFixed())  
    //console.log(queue.pop().toFixed())  
    
    //此时运行会报错
    //queue.pop(...)toFixed is not a function
    
    //为什么在我们的ts代码中没有抓到这个错误呢
    //首先它允许你像对列中添加任何类型的数据,
    //当然数据被弹出对列的时候也可以是任意类型,
    
    //我们可以看到我们可以在里面添加string类型的数据,
    //使用的时候就会出现无法捕捉的错误,
    //比如这个例子,我们弹出的第二个类型是string类型,但我们调用了
    //只有数字类型才有的方法,
    //所以在typeScript中没有抓到这个错误,
    
    //实际上该用法是假如只有number类型时才会被添加到对列里,
    一个解决办法是添加的时候创建一个约束,
    
    //   push(item: number){
    //     return this.data.push(item)
    //   }
    //queue.push('str')  //此时会出现一个错误
    
    //这是一个很坏的解决方法
    
    假如当你想创建一个字符串的对列的时候,将不得不再次修改相当大类型的代码,
    我们真正想要的是一种方法是无论什么类型被推入对列,被推出的类型都与推入的是一样的,
    这时候就可以让泛型来帮助我们,我们可以创建一个泛型类,怎么写?
    之前我们是在函数名称后面加<>,现在我们在类名称后面加<>,
    
    class Queue<T>{
       private data = []
       push(item: T){   //希望被push进去的类型是T
         return this.data.push(item)
       }
       pop(): T{   //被推出的类型应该是T
         return this.data.shift()
       }
     }
    //这时候我们创建了一个带有泛型的对列,一个类,
    
    要初始化的时候,我们需要在Queue这个构造函数后面加上你想要的类型,
    const queue = new Queue<number>()
    
    
    //我们上边说类就可以用泛型来描述,
    //interface--接口也可以接受泛型的洗礼,变得灵活起来,
    
    泛型和interface,
    定义一个interface叫KeyPair,它有两个值,一个叫key,一个叫value
    我们希望key和value这两个值都是我们在使用的时候,动态的的传入,
    现在我不确定它是什么类型,
    所以皆可以给KeyPair定义两个类型,
    
    interface KeyPair<T,U>{
       key: T;
       value: U;
     }
    
    //let kp1: KeyPair<number,string> = {key:1, value:'str'}
    //let kp2: KeyPair<string,number> = {key:'str', value:123}
    
    //定义数组类型的时候,
    //let arr: number[] = [1,2,3]
    
    //现在我们可以使用表示泛型的形式来表示,
    //let arrTwo: Array<number> = [1,2,3]
    
    //以上就是interface搭配泛型以后可以灵活地返回不同的类型,
    
    
    关于泛型的总结:
    1.创建一个拥有特定类型的容器,比如类和interface上的泛型,
      仿佛给一个容器贴标签一样,
      let arrTwo: Array<number> = [1,2,3]  
      给Array贴上了number标签,告诉arrTwo我要你是一个装满number类型的数组,
    
     const queue = new Queue<number>()
      或者告诉一个类我希望你是一个装着数字的对列,
      甚至你可以想它像一个可变的参数那样,在用的时候传入,生成一个不同类型的
      一个容器,
    
    
    2.可以用它来灵活的约束参数的类型,不需要参数是个特别死板的类型,
      比如说,我们不希望它是一个特定string类型,不希望它是一个number类型,
      而我要传入的参数必须有某某属性,某某方法,否在就会报错,
    
    
    //(第一节:generrics,ts)
    3.在函数使用的时候,函数的类型推断不会流入到函数体内,
    所以使用表达式没法明确建立类型的绑定,
    用泛型可以让我们打破这个鸿沟,
    function echo<T>(arg: T): T{
       return arg
     }
    const result = echo(true)  //result就会返回它传入的类型,
    

    相关文章

      网友评论

          本文标题:2020-11-05Typescript(2.2)

          本文链接:https://www.haomeiwen.com/subject/nkdovktx.html