7

Here is the code that the Typecript compiler curses:

use(path: PathParams, ...handlers: RequestHandler[]): this
use(path: PathParams, ...handlers: RequestHandlerParams[]): this
use(...handlers: RequestHandler[]): this
use(...handlers: RequestHandlerParams[]): this {
    // ...
    return this;
}

error TS2394: Overload signature is not compatible with function implementation.

I can not understand how I can properly do the overload. Can you tell which direction to dig?

1 Answer 1

6

Here you go:

Note: that the types of PathParams, RequestHandler, and RequestHandlerParams are invented but the point is that they are distinct and incompatible

export interface PathParams {
  path: string;
  params: {
    id: number,
    [key: string]: string | number
  }
}

export type RequestHandler = (request: RequestHandlerParams) => void;

export interface RequestHandlerParams {
  kind: 'query' | 'route'
  value: string;
}

export default class {
  use(path: PathParams, ...handlers: RequestHandler[]): this
  use(path: PathParams, ...handlers: RequestHandlerParams[]): this
  use(...handlers: RequestHandler[]): this
  use(...handlers: RequestHandlerParams[]): this;
  use(
    pathOrHandlerOrHandlerParam: PathParams | RequestHandler | RequestHandlerParams,
    ...handlers: Array<RequestHandler | RequestHandlerParams>
  ): this {
    // ...
    return this;
  }
}

Note that when creating an overload definition, the implementation signature is not available to consumers. Only the signatures that do not have an implementation are available. This is why I have added an additional signature to your example.

The reason why this works is that, in order to make the first parameter "optional" we need to give it a type that may be compatible with the array element type of either of the possible rest parameter types.

You could of course specify the parameter types in the implementation signature as any and any[] without compromising type safety for your consumers (the implementation signature is not part of the interface) but, by using a precise, well-structured union type, you can use type guards to discriminate over the arguments and verify that the implementation handles them.

This implies that you will need to determine if the first parameter is actually a PathParams via logic in the function implementation.

Sign up to request clarification or add additional context in comments.

1 Comment

What helped me from this answer, was the statement about the Implementation signature being hidden from the consuming code. I had always assumed that all signatures were available. Not anymore!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.