传递通用类类型作为通用函数的参数

时间:2018-09-29 16:31:56

标签: angular typescript generics

我正在使用一种转换器(外部库),该转换器的方法如下所述,来自 Json 。 我想构建一个通用的RESTService,但是我不知道如何将通用类类型传递给该方法。

// From the library
export declare type Clazz<T> = {
  new (...args: any[]): T;
};

// From the library
export class Converter {
  ...
  public fromJson<T>(json: any, clazz: Clazz<T>): T { ... }
  ...
}

// ******************************************************

// My Service on my Angular app
class RESTService<T> {
  ...
  public save(t: T): Observable<T> {
    return this.httpClient.post('http://...', t)
      .pipe(map(res => this.converter.fromJson(res, ???)));
  }
  ...
}

2 个答案:

答案 0 :(得分:0)

您可以将t.constructor用作Clazz<T>参数。您需要使用as告诉TypeScript正确的类型:

// From the library
declare type Clazz <T> = {
    new(...args: any[]): T;
};

// From the library
class Converter {
    public fromJson<T>(json: any, clazz: Clazz<T>) { return new clazz(); }
}

class Test {
    public testIt<T>(test: T) {
        const converter = new Converter();
        var o = converter.fromJson("{}", test.constructor as new (...args: any[]) => T);
        return o;
    }
}

class TestObj {
    testProp: string = "hello";
}

var o = new TestObj();
var t = new Test();
var a = t.testIt(o);
console.log(JSON.stringify(a));

This seems to compile and work in the TypeScript Playground,但与往常一样,您应该在自己的环境中对其进行测试。

我确实更改了fromJson以便获得可记录的结果,显然testIt与您的(Angular?)函数并不完全相同,但希望它可以使您正确进行方向。

答案 1 :(得分:0)

  1. 您使用的库非常糟糕,并且存在语义错误。 new是用于初始化类类型的实例的关键字。返回类型应始终与此类类型一致。正确的定义应为:

       
    export declare type Clazz<T> = {
      new (...args: any[]): Clazz<T>;
    };
    
  2. 解决此问题。您始终可以使用关键字asObject.create(null)来转换大多数对象类型,以避免编译器检查:

     
    class RESTService<T> {
      ...
      public save(t: T): Observable<T> {
        let clazz = Object.create(null) as Clazz<T>;
        // clazz.someValue = 'Hello world';
        return this.httpClient.post('http://...', t)
          .pipe(map(res => this.converter.fromJson(res, clazz)));
      }
      ...
    }
    

    Object.create(null)为您提供了一个没有任何方法绑定的js对象-纯结构空间。