简体   繁体   中英

Generic constraint with any type

I have to start showing my code in order to explain my problem.

My generic classes:

export class RpcPublisherMessage<T extends RpcPublisherRequest<T>> {
  constructor(public publisherRequest: T, public publishOptions: Options.Publish = {}, public timeoutMs?: number) {}
}

export class RpcPublisherRequest<T> extends RpcMessageData<T> {
  constructor(payload: T, private context: string) {
    super(payload);
  }

  public toBuffer(): Buffer {
    return Buffer.from(...);
  }
}

My problem:

  public async dispatchMessage(rpcMessage: RpcPublisherMessage<any>): Promise<IRequestMessageResponse> {
    const message = rpcMessage.publisherRequest; // I can not call toBuffer() here
  }

This is where I want to use an instance of RpcPublisherMessage<any> . Since the RpcPublishermessage has a generic constraint I expected that I am able to call toBuffer() on the publisherRequest property, but apparently I am not.

What I tried to fix that:

I thought it's maybe because of the any in RpcPublisherMessage<any> which maybe also needs the constraint given, but something like rpcMessage: RpcPublisherMessage<any extends RpcPublisherRequest<any>> in the function parameters hasn't worked. VSCode then says

[ts] Parameter 'rpcMessage' of public method from exported class has or is using private name ''.

My question:

Why am I not able to call toBuffer() on publisherRequest even though I specified a constraint for this property?

Elaborating my comments as an answer.


Aside: the following definition

export class RpcPublisherMessage<T extends RpcPublisherRequest<T>> { ... }

isn't what you want to say. Literally, you're saying that the parameter T should be assignable to RpcPublisherRequest<T> , where that second T is the same T as the first . Unless you want the payload of the RpcPublisherRequest to be an RpcPublisherMessage whose publisherRequest type is a RpcPublisherRequest whose payload is an RpcPublisherMessage whose publisherRequest is a ... :shudders: Unless you actually want a recursive type bound for T , you should change that definition.

If all you want is that T should be an RpcPublisherRequest<U> for some U , then you can get away with doing this:

export class RpcPublisherMessage<T extends RpcPublisherRequest<any>> { ... }

This is no longer a recursive type bound.


Main: the problem you have with this

public async dispatchMessage(
  rpcMessage: RpcPublisherMessage<any>
): Promise<IRequestMessageResponse> {
  const message = rpcMessage.publisherRequest.toBuffer(); // no error
  const massage = rpcMessage.publisherRequest.toButter(); // also no error
}

should not be that you can't call toBuffer() . Rather, the problem is that rpcMessage.publisherRequest is typed as any , which means you can call toBuffer() without complaint. But you can also call toButter() it without complaint, which is bad. And you get no IntelliSense suggesting methods since an any type can have any properties whatsoever, which is bad.

And this is because RpcPublisherMessage<any> specifies that T is any , which meets all constraints but doesn't give you any type hinting. If you want a tighter constraint, you can specify T to be RpcPublisherRequest<any> instead:

public async dispatchMessage(
  rpcMessage: RpcPublisherMessage<RpcPublisherRequest<any>>
): Promise<IRequestMessageResponse> {
  const message = rpcMessage.publisherRequest.toBuffer(); // no error
  const massage = rpcMessage.publisherRequest.toButter(); // error, yay!
}

That should fix your issues. If you need to keep track of the particular payload type of the request type, you could always make dispatchMessage() a generic method like this:

public async dispatchMessage<P>(
  rpcMessage: RpcPublisherMessage<RpcPublisherRequest<P>>
): Promise<IRequestMessageResponse> {
  const message = rpcMessage.publisherRequest.toBuffer(); // no error
}

where the P is your generic payload type. But you might not need to go that far.


Okay hope that helps; good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM