泛型
    不仅要创建一致定义良好的API,同时要考虑可重用性。组件不能支持当前的数据类型,同时也能支持未来的数据类型,可为此提供十分灵活的功能。
    可使用泛型来创建可重用的组件,一个组件可支持多种类型的数据。
    不用泛型的代码:

    1. function ident(arg:any):any { // any 为任意类型
    2. return arg
    3. }

    用any 很容易丢失一些信息:传入的类型和返回的类型应该是相同的。如果我们传入一个数字,我们只知道任何类型的值都有可能被驳回。
    我们需要一种方法使返回值的类型与传入参数类型是相同的。使用类型变量,它是一种特殊的变量,只用于表现类型而不是值。

    function ident <T>(arg:T):T {
            return arg
    }
    

    T帮助我们捕获用户传入的类型,我们可以使用这个类型。之后我们再次使用了T当做返回类型。就能知道参数类型和返回类型是相同的。允许我们跟踪函数里使用的类型的信息。

    我们把这个版本的ident叫做泛型,因为他可以使用多个类型。不同于any,不会丢失信息,保持准确性,传入数值类型并返回数值类型。
    定义泛型函数后,可以有两种方法使用。
    第一种,传入所有的参数,包含类型参数:

    let output = ident<string>('myString')   // output 是string
    

    T是string类型,并做为一个参数传给了函数,使用了<>而不是( )

    第二种方法更普遍。利用了类型推论—-编译器会根据传入的参数自动的帮助确定的类型:

    let output = ident('myString')
    

    没必要使用<>来明确传入的类型,编译器可以查看myString的值,然后把T设置为它的类型。如果不能够自动的推断出类型的话,只能明确的传入T的类型,在一些复杂的情况下,是可能出现的。

    使用泛型变量

    function ident<T>(arg:T):T{
      consel.log(arg.length)
      return arg
    }
    //  此时会报错,arg有可能是数字类型没有length
    

    操作T类型的数组不直接是T。由于我们操作的是数组,所以.length属性是应该存在的。我们可以像创建其他数组一样创建这个数组:

    function logging<T>(arg:T[]):T[] {
            consel.log(arg.length)
          return arg
    }
    

    泛型类型
    泛型函数的类型与非泛型函数的类型没什么不同,只是有一个类型参数在最前面,像函数声明一样:

    function ident<T>(arg:T):T {
            return arg
    }
    
    let myIdentity:<U>(arg:U) => U = ident
    
    // 可以使用不同的泛型参数名,只要在数量上的使用方式上能对应上就可以