当参数类型为泛型时,是否可以为打字稿中的参数设置默认值?

Riv*_*r H 5 generics casting typescript

我正在编写通用方法,以便在不同的前端应用程序中使用它们,其想法是能够调用该函数.postAsync<CustomModel>('www.mysite.com',..., CustomModel);,并且预期的响应是一个 CustomModel 对象。

我希望能够为第二个参数设置默认值,以便默认情况下该值将是不同的模型,并且可以在需要时覆盖。

如何为Constructable<T>接口 Constructable 意味着类型的参数设置默认值

interface Constructable<T> { new(params : any): T ;}
Run Code Online (Sandbox Code Playgroud)

我尝试设置一个带有参数的接口的默认值并将参数设置为不同的类型,但我总是收到错误Type Constructable<CustomModel> is not assignable to type Constructable<T>。我还在 CustomModel 通用方法中设置了 T 的默认类型,然后尝试了此操作并得到相同的错误。

interface Constructable<T> { new(params : any): T ;}


export default class WebapiBase {

    static async postAsync<T = CustomModel>(
        uri: string,
        body: object,
        headers: CustomHeaders = new CustomHeaders(),
        // This is the part giving errors
        model: Constructable<T> = <Constructable<CustomModel>>,): Promise<T> {
        return this.requestAsync<T>(model, HTTP_METHOD.POST, uri, headers, body);
    }

    private static async requestAsync<T>(
        model: Constructable<T>,
        method: HTTP_METHOD,
        uri: string,
        headers: CustomHeaders,
        body?: object): Promise<T> {
        const url = new URL(uri, window.location.origin);
        const request = this.buildRequest(url, method, headers, body);
        const bodyResponse = await fetch(request)
            .then(response => this.validate(response, request.headers))
            .then(validResponse => this.extractBody(validResponse))
            // Here is where the response body is being used to initialise one of the custom models that we are passing in. Code below
            .then(extractedBody => this.buildModel<T>(model, extractedBody))
            .catch((error) => { throw this.handleError(error); });
        return bodyResponse;
    }

    private static buildModel<T>(
        Model: Constructable<T>,
        params: ResponseBody,
    ): T {
        return new Model(params);
    }
}

Run Code Online (Sandbox Code Playgroud)

我预计我不必将模型传递给该方法postAsync(),并且它始终会返回 CustomModel 对象。但实际上我得到这个错误Type Constructable<CustomModel> is not assignable to type Constructable<T>

Playground 中的示例,将鼠标悬停在 args 中的 Constructable 上以查看错误

Riv*_*r H 0

我解决了这个问题,即返回默认值(在本例中为通用对象),以防模型未通过。一般来说,修复方法是:

  • 从将模型键入为Constructable接口更改为使用 的联合类型Constructable<T> | object
  • 更改将模型传递给对象的默认值。
  • buildModel()函数检查模型的类型,如果它是一个对象,则返回传入的值,如果它是一个可构造的,则创建它的实例。

查看它是如何在postAsync参数、接口ResponseModel和方法中buildModel实现的requestAsync

interface Constructable<T> { new(params : any): T ;}
type ResponseModel<T> = Constructable<T> | Object;

export default class WebapiBase {
  static async postAsync<T = Object>(
      {
          uri = '',
          body = {},
          headers = new CustomHeaders(),
      }: PostRequestParams = {},
      // Here is where the defualt is implemented
      model: ResponseModel<T> = Object): Promise<T> {
      return this.requestAsync(model, HTTP_METHOD.POST, uri, headers, body);
  }
  private static async requestAsync<T = Object>(
      // This param accepts either a class or object
      model: ResponseModel<T>,
      method: HTTP_METHOD,
      uri: string,
      headers: CustomHeaders,
      body?: object): Promise<T> {
      const url = new URL(uri, window.location.origin);
      const request = this.buildRequest(url, method, headers, body);
      const bodyResponse = await fetch(request)
          .then(response => this.validate(response, request.headers))
          .then(validResponse => this.extractBody(validResponse))
          // Class instance or object returned here
          .then(extractedBody => this.buildModel(model, extractedBody))
          .catch((error) => { throw this.handleError(error); });
      return bodyResponse;
  }

  // Method that conditionally creates an instance of the passed in model
  // Or returns the object passed in if no model specified
  private static buildModel<T = Object>(
        Model: ResponseModel<T>,
        params: any,
    ): T {
        if (typeof Model === 'object') return params;
        return new Model(params);
  }
}
Run Code Online (Sandbox Code Playgroud)