I'm currently facing challenges with TypeScript overload resolution.
When using the googleapis library with TypeScript to fetch all tag manager accounts records, the list function requires pagination if the response body contains a nextPageToken. I aim to create a function that can paginate through all records and retrieve them.
The idea is to create a curried function like this - it takes the list function as an argument and continues calling it with the nextPageToken until no more tokens are included in the returned data.
// Example 1)
const allAccounts = await paginateAll(tagmanager.accounts.list)({
// specify tagmanager.accounts.list parameters
});
// Example 2)
const allContainers = await paginateAll(tagmanager.accounts.containers.list)({
// specify tagmanager.accounts.containers.list parameters
});
I defined a signature for paginateAll
as shown below, but TypeScript seems unable to resolve the appropriate 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'.
The list
function in googleapis has 6 overloads, and I expect paginateAll
to select 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: void;
4. list(params: Params$Resource$Accounts$List, options: MethodOptions | BodyResponseCallback<Schema$ListAccountsResponse>, callback: void;
5. list(params: Params$Resource$Accounts$List, callback: BodyResponseCallback<Schema$ListAccountsResponse>): void;
6. list(callback: BodyResponseCallback<Schema$ListAccountsResponse>): void;
I would greatly appreciate any insights on why this issue is occurring...
==== UPDATE ====
I have replicated the error from my question using TypeScript Playground. (I've simplified it by removing the curry aspect)
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: void;
declare function func(params: Params, options: Options2 | Callback<Response2>, callback: 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);