I have the following class:
class Processor<TReq, TRes> {
constructor(
private handler: (input: TReq) => TRes
) {}
public handleRequest(input: TReq): TRes {
...
const res = this.handler(input);
...
}
}
In this design, I can do this:
const myProcessor = new Processor<string, string>(
(input: string) => `Hello ${input}`
);
myProcessor.handleRequest('Hello');
My issue is that I want to be able to pass never
to TReq
, and when that happens, I would like handleRequest
to be of type () => TRes
, and handler
as well:
const myProcessor = new Processor<never, string>(
() => 'Hi'
);
myProcessor.handleRequest();
How can I achieve this?
I think the closest you can get is the following
TReq
handleRequst
argument optionalclass Processor<TReq, TRes> {
private handler: [TReq] extends [never] ? () => TRes : (input: TReq) => TRes;
constructor(
handler: [TReq] extends [never] ? () => TRes : (input: TReq) => TRes,
) {
this.handler = handler;
}
public handleRequest(): TReq extends never ? TRes : never;
public handleRequest(input: TReq): TReq extends never ? never : TRes;
public handleRequest(input?: TReq): TRes {
const res =
typeof input === 'undefined'
? (this.handler as () => TRes)()
: (this.handler as (input: TReq) => TRes)(input);
return res;
}
}
upd: added handleRequest
overloads with generic constraint as suggested in comments. Still not perfect, but i'm afraid this is the best you can get from TS