Here is the information you requested:
Please note that the PathParams
, RequestHandler
, and RequestHandlerParams
types are hypothetical, but the key takeaway is that they are intentionally different and cannot be mixed interchangeably.
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;
}
}
It's important to note that when defining multiple function overloads, the implementation details are hidden from consumers. Consumers only see the signatures without implementation. That's why an additional signature was included in the example.
The way this works is by making the first parameter "optional" by giving it a type that could match the array elements of either rest parameter type.
While you could use any
in the implementation signature without impacting consumer type safety (as they don't see it), using a specific union type allows for type guards to ensure correct handling of arguments.
This means that within the function implementation, you'll need to determine if the first parameter is indeed a PathParams
through conditional checks.