【问题标题】:typescript semantic difference between generic class methods and generic classes泛型类方法和泛型类之间的打字稿语义差异
【发布时间】:2018-08-14 06:12:31
【问题描述】:

我有点困惑为什么下面的示例代码在我使用类泛型时有效,但在我使用方法泛型时无效。

首先我有简单的RequestResponse 类:

abstract class BaseRequest {
  baseProperty: string;
}

class ChildRequest extends BaseRequest {
  childProperty: string;
}

abstract class BaseResponse<R extends BaseRequest> {
  data: any;
  request: R;
}

class ChildResponse extends BaseResponse<ChildRequest> {
}

为了让我的继承简单,我想要使用下面的泛型方法代码(注意类不是泛型,只有方法和扩展基类不需要泛型):

abstract class RequestClient {
  abstract request<RQ extends BaseRequest, RP extends BaseResponse<RQ>>(request: RQ): RP;
}


class ChildClient extends RequestClient {
  request(request: ChildRequest): ChildResponse {
    return undefined;   // just testing the code structure right now
  }
}

但是编译器在ChildClient.request上比较:

TS2416: Property 'request' in type 'ChildClient' is not assignable to the same property in base type 'RequestClient'.
  Type '(request: ChildRequest) => ChildResponse' is not assignable to type '<RQ extends BaseRequest, RP extends BaseResponse<RQ>>(request: RQ) => RP'.
    Types of parameters 'request' and 'request' are incompatible.
      Type 'RQ' is not assignable to type 'ChildRequest'.
        Type 'BaseRequest' is not assignable to type 'ChildRequest'.
          Property 'childProperty' is missing in type 'BaseRequest'.

但是,使用类泛型可以正常工作:

abstract class RequestClient<RQ extends BaseRequest, RP extends BaseResponse<RQ>> {
  abstract request(request: RQ): RP;
}

class ChildClient extends RequestClient<ChildRequest, ChildResponse> {
  request(request: ChildRequest): ChildResponse {
    return undefined;
  }
}

我想避免类泛型,因为它开始创建类继承涓滴爆炸式增长,我最终拥有大量无用的子类,只是为了让泛型方法正确编译。

为什么类泛型可以工作,但方法泛型不行?这里的语义区别是什么?

谢谢!

【问题讨论】:

    标签: typescript generics


    【解决方案1】:

    因为在泛型方法示例中,您的子类违反了基类定义的约定。

    基类承诺该类的一个实例允许调用者选择任何类型的请求和响应,但子类覆盖请求方法并限制契约:不,我只能发送一个 ChildRequest,你会只取回一个 ChildResponse。

    考虑以下情况:

    const client: RequestClient = new ChildClient();
    

    这是有效的,因为 ChildClient 扩展了 RequestClient。所以,既然客户端是RequestClient,你可以这样做

    const response: MyResponse = client.request<MyRequest, MyResponse>(new MyRequest());
    

    如果编译器接受了你想要的,会调用哪个方法?会发生什么?

    【讨论】:

    • 啊,是的。在那里的杂草中迷路了。感谢您的示例情况。这确实清楚地说明了为什么编译器对我大吼大叫。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2021-11-26
    • 1970-01-01
    • 2017-09-15
    • 2020-01-23
    • 2021-06-09
    • 2021-08-13
    相关资源
    最近更新 更多