I am struggling with typescript overload resolution.
I am using googleapis library with typescript and trying to fetch all tagmanager accounts records. Since googleapis list function requires pagination if response body contains nextPageToken, I would like to create function that paginates all and grabs all records.
My idea is to create a curry function like this. It takes list function as an argument, and it keeps calling the list function with nextPageToken until nextPageToken is not included in returned data from the list function.
// ex. 1)
const allAccounts = await paginateAll(tagmanager.accounts.list)({
// specify tagmanager.accounts.list parameter
});
// ex. 2)
const allContainers = await paginateAll(tagmanager.accounts.containers.list)({
// specify tagmanager.accounts.containers.list parameter
});
I created a paginateAll signature like below, but it seems like typescript doesn't resolve proper overload.
export const paginateAll = <P1, P2, R>(
list: (params?: P1, options?: P2) => Promise<R>,
): ((arg1: P1, arg2: P2) => Promise<Array<R>>) => async (a, b) => {
// some procedure...
};
const fetchAllAccounts = paginateAll(tagmanager.accounts.list)
^^^
=== ERROR ===
Argument of type '{ (params: Params$Resource$Accounts$List, options: StreamMethodOptions): GaxiosPromise<Readable>; (params?: Params$Resource$Accounts$List | undefined, options?: MethodOptions | undefined): GaxiosPromise<...>; (params: Params$Resource$Accounts$List, options: StreamMethodOptions | BodyResponseCallback<...>, callback: ...' is not assignable to parameter of type '(params?: BodyResponseCallback<Schema$ListAccountsResponse> | undefined, options?: unknown) => Promise<unknown>'.
Types of parameters 'params' and 'params' are incompatible.
Type 'BodyResponseCallback<Schema$ListAccountsResponse> | undefined' is not assignable to type 'Params$Resource$Accounts$List'.
Type 'undefined' is not assignable to type 'Params$Resource$Accounts$List'.
googleapis list function has 6 overloads like below. I expect paginateAll to pick the 2nd signature.
1. list(params: Params$Resource$Accounts$List, options: StreamMethodOptions): GaxiosPromise<Readable>;
2. list(params?: Params$Resource$Accounts$List, options?: MethodOptions): GaxiosPromise<Schema$ListAccountsResponse>;
3. list(params: Params$Resource$Accounts$List, options: StreamMethodOptions | BodyResponseCallback<Readable>, callback: BodyResponseCallback<Readable>): void;
4. list(params: Params$Resource$Accounts$List, options: MethodOptions | BodyResponseCallback<Schema$ListAccountsResponse>, callback: BodyResponseCallback<Schema$ListAccountsResponse>): void;
5. list(params: Params$Resource$Accounts$List, callback: BodyResponseCallback<Schema$ListAccountsResponse>): void;
6. list(callback: BodyResponseCallback<Schema$ListAccountsResponse>): void;
I would really appreciate if you guys tell me why this is happening...
==== UPDATE ====
I reproduced the error in my question with TypeScript Playground. (I made it not curry to make it simpler)
type Params = {
value1: string;
value2: string;
}
type Options1 = {
option1Value: string;
};
type Options2 = {
option2Value: string;
};
type Resonse1 = {
response1Value: string;
}
type Response2 = {
response2Value: string;
}
type Callback<T> = () => T
declare function func(params: Params, options: Options1): Promise<Resonse1>;
declare function func(params?: Params, options?: Options2): Promise<Response2>;
declare function func(params: Params, options: Options1 | Callback<Resonse1>, callback: Callback<Resonse1>): void;
declare function func(params: Params, options: Options2 | Callback<Response2>, callback: Callback<Response2>): void;
declare function func(params: Params, callback: Callback<Response2>): void;
declare function func(callback: Callback<Response2>): void;
const anotherFunc = async <P1, P2, R>(
fn: (params?: P1, options?: P2) => Promise<R>,
): Promise<R> => {
return fn();
}
const test = anotherFunc(func);