Skip to content

Commit e95444d

Browse files
authored
fix(types): improve type extraction for namespaced responses and correct 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.
1 parent b2dc51c commit e95444d

File tree

4 files changed

+19
-24
lines changed

4 files changed

+19
-24
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"lint:fix": "prettier --write '{src,test,scripts}/**/*' '!scripts/generated/*' README.md package.json",
1414
"pretest": "npm run -s lint",
1515
"test": "vitest run --coverage",
16-
"test:ts": "npx tsc --noEmit --declaration --noUnusedLocals --allowImportingTsExtensions test/validate-typescript.ts",
16+
"test:ts": "npx tsc --noEmit --declaration --noUnusedLocals --allowImportingTsExtensions --strict test/validate-typescript.ts",
1717
"update-endpoints": "npm-run-all update-endpoints:*",
1818
"update-endpoints:fetch-json": "node scripts/update-endpoints/fetch-json",
1919
"update-endpoints:typescript": "node scripts/update-endpoints/typescript"

src/iterator.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,5 @@ export function iterator(
5858
}
5959
},
6060
}),
61-
};
61+
} as AsyncIterable<any>;
6262
}

src/paginate.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,15 @@ export function paginate(
2323
return gather(
2424
octokit,
2525
[],
26-
iterator(octokit, route, parameters)[
27-
Symbol.asyncIterator
28-
]() as AsyncIterableIterator<any>,
26+
iterator(octokit, route, parameters)[Symbol.asyncIterator](),
2927
mapFn,
3028
);
3129
}
3230

3331
function gather(
3432
octokit: Octokit,
3533
results: PaginationResults,
36-
iterator: AsyncIterableIterator<any>,
34+
iterator: AsyncIterator<any>,
3735
mapFn?: MapFunction,
3836
): Promise<PaginationResults> {
3937
return iterator.next().then((result) => {

src/types.ts

+15-18
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ type KnownKeys<T> = Extract<
3535
} extends { [_ in keyof T]: infer U }
3636
? U
3737
: never,
38-
keyof T
38+
// Exclude keys that are known to not contain the data
39+
Exclude<
40+
keyof T,
41+
"repository_selection" | "total_count" | "incomplete_results"
42+
>
3943
>;
4044
type KeysMatching<T, V> = {
4145
[K in keyof T]: T[K] extends V ? K : never;
@@ -50,7 +54,8 @@ type GetResultsType<T> = T extends { data: any[] }
5054
? T["data"][KnownKeysMatching<T["data"], any[]>]
5155
: never;
5256

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

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

@@ -199,9 +204,7 @@ export interface PaginateInterface {
199204
*/
200205
<T>(
201206
options: OctokitTypes.EndpointOptions,
202-
): AsyncIterableIterator<
203-
OctokitTypes.OctokitResponse<PaginationResults<T>>
204-
>;
207+
): AsyncIterable<OctokitTypes.OctokitResponse<PaginationResults<T>>>;
205208

206209
// Using route string as first parameter
207210

@@ -215,7 +218,7 @@ export interface PaginateInterface {
215218
<R extends keyof PaginatingEndpoints>(
216219
route: R,
217220
parameters?: PaginatingEndpoints[R]["parameters"],
218-
): AsyncIterableIterator<
221+
): AsyncIterable<
219222
OctokitTypes.OctokitResponse<DataType<PaginatingEndpoints[R]["response"]>>
220223
>;
221224

@@ -231,9 +234,7 @@ export interface PaginateInterface {
231234
parameters?: R extends keyof PaginatingEndpoints
232235
? PaginatingEndpoints[R]["parameters"]
233236
: OctokitTypes.RequestParameters,
234-
): AsyncIterableIterator<
235-
OctokitTypes.OctokitResponse<PaginationResults<T>>
236-
>;
237+
): AsyncIterable<OctokitTypes.OctokitResponse<PaginationResults<T>>>;
237238

238239
// Using request method as first parameter
239240

@@ -247,7 +248,7 @@ export interface PaginateInterface {
247248
<R extends OctokitTypes.RequestInterface>(
248249
request: R,
249250
parameters?: Parameters<R>[0],
250-
): AsyncIterableIterator<
251+
): AsyncIterable<
251252
NormalizeResponse<OctokitTypes.GetResponseTypeFromEndpointMethod<R>>
252253
>;
253254
};
@@ -414,9 +415,7 @@ export interface ComposePaginateInterface {
414415
<T>(
415416
octokit: Octokit,
416417
options: OctokitTypes.EndpointOptions,
417-
): AsyncIterableIterator<
418-
OctokitTypes.OctokitResponse<PaginationResults<T>>
419-
>;
418+
): AsyncIterable<OctokitTypes.OctokitResponse<PaginationResults<T>>>;
420419

421420
// Using route string as first parameter
422421

@@ -433,7 +432,7 @@ export interface ComposePaginateInterface {
433432
octokit: Octokit,
434433
route: R,
435434
parameters?: PaginatingEndpoints[R]["parameters"],
436-
): AsyncIterableIterator<
435+
): AsyncIterable<
437436
OctokitTypes.OctokitResponse<DataType<PaginatingEndpoints[R]["response"]>>
438437
>;
439438

@@ -452,9 +451,7 @@ export interface ComposePaginateInterface {
452451
parameters?: R extends keyof PaginatingEndpoints
453452
? PaginatingEndpoints[R]["parameters"]
454453
: OctokitTypes.RequestParameters,
455-
): AsyncIterableIterator<
456-
OctokitTypes.OctokitResponse<PaginationResults<T>>
457-
>;
454+
): AsyncIterable<OctokitTypes.OctokitResponse<PaginationResults<T>>>;
458455

459456
// Using request method as first parameter
460457

@@ -471,7 +468,7 @@ export interface ComposePaginateInterface {
471468
octokit: Octokit,
472469
request: R,
473470
parameters?: Parameters<R>[0],
474-
): AsyncIterableIterator<
471+
): AsyncIterable<
475472
NormalizeResponse<OctokitTypes.GetResponseTypeFromEndpointMethod<R>>
476473
>;
477474
};

0 commit comments

Comments
 (0)