1.泛型定义

  • 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
  • 泛型T作用域只限于函数内部使用

2.泛型函数
创建一个identity函数。这个函数会返回任何传入它的值。 你可以把这个函数当成是echo命令。

function identity(arg: number): number {
  return arg;
}
 /**
   * 使用any类型来定义函数
   * 使用any类型后这个函数已经能接收任何类型的arg参数,
   但是却丢失了一些信息
   * 传入的类型与返回的类型应该是相同的。
   * 如果我们传入一个数字,我们只知道任何类型的值都有可能被返回。
   */
  function identity(arg: any): any {
    return arg;
  }

我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 _类型变量_,它是一种特殊的变量,只用于表示类型而不是值。

 /**
     * 给identity添加了类型变量T。
     * T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。
     * 之后我们再次使用了 T当做返回值类型。
     *  这允许我们跟踪函数里使用的类型的信息。
     * 我们把这个版本的identity函数叫做泛型,因为它可以适用于多个类型。 
     * 不同于使用 any,它不会丢失信息.
     */
    function identity<T>(arg:T):T{
        return arg;
    }

我们定义了泛型函数后,可以用两种方法使用。

//第一种,传入所有的参数,包含类型参数
    let output1 = identity<string>("myString");
//第二种方法更普遍。利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型
    let output2 = identity("myString");

3.泛型类

class MyArray<T> {
    private list: T[] = [];
    add(value: T) {
      this.list.push(value);
    }
    getMax(): T {
      let result = this.list[0];
      for (let i = 0; i < this.list.length; i++) {
        if (this.list[i] > result) {
          result = this.list[i];
        }
      }
      return result;
    }
  }
  let arr = new MyArray();
  arr.add(1);
  arr.add(2);
  arr.add(3);
  let ret = arr.getMax();
  console.log(ret);

4.泛型接口
泛型接口可以用来约束函数

    interface Calculate{
        <T>(a:T, b:T):T
    }
    let add:Calculate = function<T>(a:T, b:T){
        return a;
    }
    console.log(add(1,2));//1

5.多个类型参数
泛型可以有多个

function swap<A, B>(tuple: [A, B]): [B, A] {
    return [tuple[1], tuple[0]];
  }
  let swapped = swap(['a', 1]);
  console.log(swapped);//[ 1, 'a' ]

6.默认泛型类型

function createArray<T=number>(length:number, value:T):Array<T>{
        let result:T[] = [];
        for (let i = 0; i < length; i++) {
            result[i] = value;
        }
        return result;
    }
    let result = createArray(3, 'fung');
    console.log(result);//[ 'fung', 'fung', 'fung' ]

7.泛型约束

function logger<T> (val:T){
        // console.log(val.length); //Erro
    }
    interface LengthWise{
        length:number
    }
    function logger2<T extends LengthWise>(val: T){
        console.log(val.length);
    }
    logger2('fung');//4
    logger2(1);//类型“1”的参数不能赋给类型“LengthWise”的参数

8.泛型接口

interface Cart<T> {
    list: T[];
  }
  let cart: Cart<{ name: string; price: number }> = {
    list: [{ name: "fung", price: 10 }]
  };
  console.log(cart.list[0].name, cart.list[0].price); //fung 10

9.泛型类型别名
泛型类型别名可以表达更复杂的类型

type Cart<T> = { list: T[] } | T[];
  let c1: Cart<string> = { list: ["1"] };
  let c2: Cart<number> = [1];

10.泛型接口 VS 泛型类

  • 接口创建了一个新的名字,它可以在其他任意地方被调用。

而类型别名并不创建新的名字,例如报错信息就不会使用别名

  • 类型别名不能被 extends和 implements,这时我们应该尽量使用接口代替类型别名
  • 当我们需要使用联合类型或者元组类型的时候,类型别名会更合适

大煜儿
106 声望7 粉丝

用心走路,给每一个细节打一个结。