Skip to content

Commit

Permalink
fix(types): improve type extraction for namespaced responses and corr…
Browse files Browse the repository at this point in the history
…ect async iterator types (#637)

The `iterator()` function returns an object containing a key of `Symbol.asyncIterator`, which is an object with a `next()` function. Only the top-level has the `Symbol.asyncIterator`, and the `next()` function is not present at the top-level

The `GetResultsType<T>` sometimes doesn't return the paginated data and returns the whole data object. For some reason TypeScript sometimes get's confused and returns all the keys in the object in the call `KnownKeysMatching<T["data"], any[]>`
In order to remedy that, we remove keys that we know do not contain the data (`"repository_selection" | "total_count" | "incomplete_results"`) and we then always get the data.

The `NormalizeResponse<T>` type would return the intersection of the original data from the request and the paginated data. To remedy that, we use `Omit<T, K>` to remove the `data` from the request data and only return the paginated data instead.
  • Loading branch information
wolfy1339 committed Sep 29, 2024
1 parent b2dc51c commit e95444d
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 24 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"lint:fix": "prettier --write '{src,test,scripts}/**/*' '!scripts/generated/*' README.md package.json",
"pretest": "npm run -s lint",
"test": "vitest run --coverage",
"test:ts": "npx tsc --noEmit --declaration --noUnusedLocals --allowImportingTsExtensions test/validate-typescript.ts",
"test:ts": "npx tsc --noEmit --declaration --noUnusedLocals --allowImportingTsExtensions --strict test/validate-typescript.ts",
"update-endpoints": "npm-run-all update-endpoints:*",
"update-endpoints:fetch-json": "node scripts/update-endpoints/fetch-json",
"update-endpoints:typescript": "node scripts/update-endpoints/typescript"
Expand Down
2 changes: 1 addition & 1 deletion src/iterator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,5 @@ export function iterator(
}
},
}),
};
} as AsyncIterable<any>;
}
6 changes: 2 additions & 4 deletions src/paginate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,15 @@ export function paginate(
return gather(
octokit,
[],
iterator(octokit, route, parameters)[
Symbol.asyncIterator
]() as AsyncIterableIterator<any>,
iterator(octokit, route, parameters)[Symbol.asyncIterator](),
mapFn,
);
}

function gather(
octokit: Octokit,
results: PaginationResults,
iterator: AsyncIterableIterator<any>,
iterator: AsyncIterator<any>,
mapFn?: MapFunction,
): Promise<PaginationResults> {
return iterator.next().then((result) => {
Expand Down
33 changes: 15 additions & 18 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ type KnownKeys<T> = Extract<
} extends { [_ in keyof T]: infer U }
? U
: never,
keyof T
// Exclude keys that are known to not contain the data
Exclude<
keyof T,
"repository_selection" | "total_count" | "incomplete_results"
>
>;
type KeysMatching<T, V> = {
[K in keyof T]: T[K] extends V ? K : never;
Expand All @@ -50,7 +54,8 @@ type GetResultsType<T> = T extends { data: any[] }
? T["data"][KnownKeysMatching<T["data"], any[]>]
: never;

type NormalizeResponse<T> = T & { data: GetResultsType<T> };
// Ensure that the type always returns the paginated results and not a mix of paginated results and the response object
type NormalizeResponse<T> = Omit<T, "data"> & { data: GetResultsType<T> };

type DataType<T> = "data" extends keyof T ? T["data"] : unknown;

Expand Down Expand Up @@ -199,9 +204,7 @@ export interface PaginateInterface {
*/
<T>(
options: OctokitTypes.EndpointOptions,
): AsyncIterableIterator<
OctokitTypes.OctokitResponse<PaginationResults<T>>
>;
): AsyncIterable<OctokitTypes.OctokitResponse<PaginationResults<T>>>;

// Using route string as first parameter

Expand All @@ -215,7 +218,7 @@ export interface PaginateInterface {
<R extends keyof PaginatingEndpoints>(
route: R,
parameters?: PaginatingEndpoints[R]["parameters"],
): AsyncIterableIterator<
): AsyncIterable<
OctokitTypes.OctokitResponse<DataType<PaginatingEndpoints[R]["response"]>>
>;

Expand All @@ -231,9 +234,7 @@ export interface PaginateInterface {
parameters?: R extends keyof PaginatingEndpoints
? PaginatingEndpoints[R]["parameters"]
: OctokitTypes.RequestParameters,
): AsyncIterableIterator<
OctokitTypes.OctokitResponse<PaginationResults<T>>
>;
): AsyncIterable<OctokitTypes.OctokitResponse<PaginationResults<T>>>;

// Using request method as first parameter

Expand All @@ -247,7 +248,7 @@ export interface PaginateInterface {
<R extends OctokitTypes.RequestInterface>(
request: R,
parameters?: Parameters<R>[0],
): AsyncIterableIterator<
): AsyncIterable<
NormalizeResponse<OctokitTypes.GetResponseTypeFromEndpointMethod<R>>
>;
};
Expand Down Expand Up @@ -414,9 +415,7 @@ export interface ComposePaginateInterface {
<T>(
octokit: Octokit,
options: OctokitTypes.EndpointOptions,
): AsyncIterableIterator<
OctokitTypes.OctokitResponse<PaginationResults<T>>
>;
): AsyncIterable<OctokitTypes.OctokitResponse<PaginationResults<T>>>;

// Using route string as first parameter

Expand All @@ -433,7 +432,7 @@ export interface ComposePaginateInterface {
octokit: Octokit,
route: R,
parameters?: PaginatingEndpoints[R]["parameters"],
): AsyncIterableIterator<
): AsyncIterable<
OctokitTypes.OctokitResponse<DataType<PaginatingEndpoints[R]["response"]>>
>;

Expand All @@ -452,9 +451,7 @@ export interface ComposePaginateInterface {
parameters?: R extends keyof PaginatingEndpoints
? PaginatingEndpoints[R]["parameters"]
: OctokitTypes.RequestParameters,
): AsyncIterableIterator<
OctokitTypes.OctokitResponse<PaginationResults<T>>
>;
): AsyncIterable<OctokitTypes.OctokitResponse<PaginationResults<T>>>;

// Using request method as first parameter

Expand All @@ -471,7 +468,7 @@ export interface ComposePaginateInterface {
octokit: Octokit,
request: R,
parameters?: Parameters<R>[0],
): AsyncIterableIterator<
): AsyncIterable<
NormalizeResponse<OctokitTypes.GetResponseTypeFromEndpointMethod<R>>
>;
};
Expand Down

0 comments on commit e95444d

Please sign in to comment.