TS:泛型的使用方法

TS:泛型

1. 前言

  • 有时候,我们想让一个函数的参数和返回类型是相同的,就可以使用类型变量

  • 类型变量是一种特殊的变量,用于表示类型而不是值。

    function identity<T>(arg : T) : T{
          
          
        return arg;
    }
    
  • 定义了泛型函数后,可以用两种方法使用。

  • 一种是传入所有的参数,包括类型参数:

    let out = identity<string>("yivi");
    
  • 另一种是使用类型推论——即编译器会自动推断类型:

    let out = identity("yivi");
    
  • 类型推论帮助我们保持代码精简和高可读性。

2. 泛型变量

  • 来看看一个例子:

    function foo<T>(arg : T): T{
          
          
        console.log(arg.length);	// error,arg的类型为T,无明确指示方法,因此报错。
        return arg;
    }
    
  • 当我们想操作T类型的数组时,.length的属性是存在的,因此不会报错:

    function foo<T>(args : T[]):T[]{
          
          
        console.log(args.length);
        return args;
    }
    
    // or
    
    function foo<T>(args : Array<T>) : Array<T>{
          
          
        console.log(args.length);
        return args;
    }
    

3. 泛型类型

  • 我们可以使用不同的泛型参数名,只要保证数量和使用方式一致即可;

  • 也可以使用带有调用签名的对象字面量来定义泛型函数;

    function identity<T>(arg : T) : T{
          
          
        return arg;
    }
    
    let myIdentity : <U>(arg : U) => U = identity;
    
    // or 
    
    let myIdentity : {
          
          <T>(arg : T):T} = identity;
    
  • 将上面的对象字面量拿出来写成一个接口:

    interface IdentityInterface{
          
          
        <T>(arg : T) : T;
    }
    
    function identity<T> (arg : T) : T{
          
          
        return arg;
    }
    
    let myidentity : IdentityInterface = identity;
    
  • 也可以将泛型参数当作整个接口的一个参数,这样就保证我们知道使用的是哪个泛型类型:

    interface IdentityInterface<T>{
          
          
        (arg : T) : T;
    }
    
    function identity<T> (arg : T) : T{
          
          
        return arg;
    }
    
    let myidentity : IdentityInterface<string> = identity;
    
  • 泛型类与泛型接口差不多,都使用<>来进行约束:

    class Foo<T>{
          
          
        state : T;
        add : (x : T, y : T) => T;
    }
    
    let myfoo = new Foo<number>();
    myfoo.state = 1;
    myfoo.add = (x,y)=>{
          
          
        return x + y;
    }
    

4. 泛型约束

  • 上面的例子中,我们提到了.length这个属性如果用在泛型上,就会报错;

  • 因此,我们只需要实现一个接口,让该泛型有这个属性,就可以防止编译器报错了;

    interface Length{
          
          
        length : number;
    }
    
    function identity<T extends Length>(arg : T) : T{
          
          
        console.log(arg.length);
        return arg;
    }
    
  • 虽然编译器不会报错了,但如果使用了没有该属性的类型,也是同样会报错;

  • 所以我们需要传入符合约束的值,且包含必须的属性;

    identity({
          
          length : 10,value : 100});
    

5. 在泛型中使用 类 类型

  • 在typescript中使用泛型创建工厂函数时,需要引用构造函数的类类型。

    function create<T> (c : {
          
          new() : T}) : T{
          
          
        return new c();
    }
    
    class Foo{
          
          
        name : string;
    }
    
    let a : Foo = create(Foo);
    a.name = 'yivi'
    console.log(a.name)
    

猜你喜欢

转载自blog.csdn.net/yivisir/article/details/109560081