I have a type that is an intersection of types that represents a list of method signatures:
type query =
| ((query: getAuthorizationState) => AuthorizationState)
| ((query: setTdlibParameters) => Ok)
| ((query: checkDatabaseEncryptionKey) => Ok)
| ((query: setAuthenticationPhoneNumber) => Ok)
| ((query: resendAuthenticationCode) => Ok)
| ((query: checkAuthenticationCode) => Ok)
| ((query: checkAuthenticationPassword) => Ok)
| ((query: requestAuthenticationPasswordRecovery) => Ok)
| ((query: recoverAuthenticationPassword) => Ok)
| ((query: checkAuthenticationBotToken) => Ok)
| ((query: logOut) => Ok)
| ((query: close) => Ok)
| ((query: destroy) => Ok)
// ...
This goes on for 301 lines, and is meant to serve as a mapping between parameters and results. Then, I created a series of types that perform some gymnastics in order to transform the query
type:
type ParamDistribute<T> = T extends (q: infer U) => infer V ? U : never;
type ReturnDistribute<T> = T extends (q: infer U) => infer V ? V : never;
type QueryDistribute<T> = T extends (q: infer U) => infer V ? (q: U) => V | error | null : never;
type PromiseDistribute<T> = T extends (q: infer U) => infer V ? (q: U) => Promise<V> : never;
type FutureDistribute<T> = T extends (q: infer U) => infer V ? (q: U) => Future<Error, V> : never;
export type Query = ParamDistribute<query>;
export type QueryResult = ReturnDistribute<query>;
export type QueryFunc = QueryDistribute<query>;
export type QueryFuncPromise = PromiseDistribute<query>;
export type QueryFuncFuture = FutureDistribute<query>;
QueryFunc
is the same as query
, except all of the return types are intersected with error
(not Error
, but a custom interface that I have) and null
. QueryFuncPromise
is the same as query
, except all of the return types are promises, etc.
Now, I have a class that has a function that implements this type signature. I've tried to apply the query
type using an interface and made the function generic:
interface TDClientFunctions
{
query: TDL.QueryFuncFuture;
}
export class TDClient extends EventEmitter implements TDClientFunctions
{
// ...
public query<T extends TDL.Query, V extends TDL.QueryResult>(query: T):
Fluture.FutureInstance<TDL.error, V>
{
// ...
}
}
However, I still don't get the correct type validation when I try to use the method:
There is only one interface in the query
intersection that fits the parameter I passed:
export type testCallEmpty = { _: "testCallEmpty", } // ... type query = // ... | ((query: testCallEmpty) => Ok) // ...
So why does the return type not resolve to Ok
? Why is the type parameter V
not properly inferred?
In other words, I'm trying to provide function overload signatures without actually writing them as overloads because there are 300 of them, and my class is going to have more than one method that follows this pattern (hence QueryFunc
, QueryFuncPromise
, QueryFuncFuture
, etc.). Is this possible in TypeScript?