plugin-paginate-rest.js icon indicating copy to clipboard operation
plugin-paginate-rest.js copied to clipboard

TypeScript types appear to be incorrect for paginate() on apps.listReposAccessibleToInstallation

Open reececomo opened this issue 3 years ago • 13 comments

Hey there.

When running await paginate(...) on apps.listReposAccessibleToInstallation, the TypeScript inferred data type is not correct.

  // context is an Octokit with an installation.id

  const repos = await context.paginate(context.apps.listReposAccessibleToInstallation, {
    per_page: 100,
  });

  // TypeScript compiler/VSCode sees `repos` as:
  // {
  //   total_count: number,
  //   repositories: { id: number,  /*...*/ }[ ],
  //   repository_selection: ?string
  // }

But really at runtime it contains repositories data array:

  console.log(repos)
  // [
  //   { id: 123,  /*...*/ },
  //   { id: 456,  /*...*/ }
  // ]

Workaround

  // FIXME: Have been doing this as a workaround.
  const installationRepos = repos.repositories ?? repos;

  installationRepos.forEach(/*...*/);

reececomo avatar Aug 24 '21 11:08 reececomo

Hmm I have a test for this exact endpoint and TS compiles without error:

https://github.com/octokit/plugin-paginate-rest.js/blob/184262e8e5b65f49c58322dcad1313320022b8c3/test/validate-typescript.ts#L173-L187

Might this be a problem with a different TS config or TS version?

Note that we do create a union between the actual endpoint types which is { total_count, repositories, ... } and our normalized format that we do within @octokit/plugin-paginate-rest which is { ...repositoryProperties}[]. We do that because some of the returned properties from the API cannot be derived from another place, so you basically get an array with custom properties such as .total_count

gr2m avatar Aug 24 '21 18:08 gr2m

closing due to inactivity

gr2m avatar Sep 12 '21 22:09 gr2m

Might this be a problem with a different TS config or TS version?

Possibly! I believe I was on latest, not sure if VSCode pulls in a different bin though 👍

Thanks for having a look @gr2m

reececomo avatar Sep 17 '21 00:09 reececomo

Hi,

we have exact same issue.

Code:

      repos = await this.appInstallsClient.paginate(
        this.appInstallsClient.apps.listReposAccessibleToInstallation,
        {
          per_page: 100,
          headers: {
            'If-None-Match': this.reposResponse?.headers.etag,
          },
        },
        response =>
          response.data.filter(repository => isActiveRepository(repository)),
      );

Typescript expects an object ( { repositories, total_count, ..} ). Typescript Version: ^4.4.4

nodify-at avatar Nov 02 '21 12:11 nodify-at

I am also seeing this issue. @gr2m can you reopen please?

JamieMagee avatar Nov 02 '21 21:11 JamieMagee

Note that @octokit is currently unmaintained, subscribe to https://github.com/octokit/octokit.js/discussions/620#discussioncomment-1472174 for updates

gr2m avatar Nov 02 '21 22:11 gr2m

I saw the same problem today, after updating to [email protected] and [email protected]. Typescript complained about that it's no longer an array with .length attribute, but rather the object.

Anyway @reececomo thanks a lot for providing a workaround. That works flawless 👍

Shegox avatar Apr 01 '22 06:04 Shegox

No problem @Shegox! Sorry it has to be this way 😓

reececomo avatar Apr 01 '22 06:04 reececomo

I can confirm that this is happening to me locally when cloning this repo in VSCode with TypeScript 5.0.4, but not when running the test:ts script with the same TypeScript version.

The type of the returned value for the pagination is not an array.

https://github.com/octokit/plugin-paginate-rest.js/blob/9240b2f12b273daebbd28b82d5e84e25fba457c7/src/types.ts#L178-L189

Maybe the returned type should be Promise<NormalizeResponse<OctokitTypes.GetResponseTypeFromEndpointMethod<R>>["data"][]>;

wolfy1339 avatar May 19 '23 18:05 wolfy1339

I've stumbled into this issue as well. If it helps anyone else until this is resolved, I'm doing this as a workaround:

// N.B. I've only included the properties I happen to use here.
type InstallationRepository = {
  name: string;
  full_name: string;
  owner: {
    login: string;
  };
  default_branch: string;
  archived: boolean;
  fork: boolean;
  html_url: string;
  is_template: boolean;
  topics: string[];
};

const repositories = (await octokit.paginate(
  octokit.rest.apps.listReposAccessibleToInstallation,
  { per_page: 100 }
)) as unknown as InstallationRepository[];

martincostello avatar Aug 29 '23 15:08 martincostello

I have the same issue i did this to solve

      const repositories = (await octokit.paginate(
        octokit.rest.apps.listReposAccessibleToInstallation,
      )) as unknown as Awaited<
        ReturnType<typeof octokit.rest.apps.listReposAccessibleToInstallation>
      >["data"]["repositories"];

Siumauricio avatar Feb 04 '24 09:02 Siumauricio

For completeness, other than listReposAccessibleToInstallation, another method that is affected by this issue is listInstallationsForAuthenticatedUser.

kamilogorek avatar Feb 28 '24 10:02 kamilogorek

Here is what I've figured,

In the pagination code, we check for and delete the following keys from the data object. https://github.com/octokit/plugin-paginate-rest.js/blob/0de101185bd8bd9f6753fb8344f1a5df113ad2b6/src/normalize-paginated-list-response.ts#L39-L41

That isn't represented in the types.

Here is a little snippet that can return only the paginated data for the types for any endpoint

type Data = Awaited<ReturnType<typeof octokit.rest.apps.listReposAccessibleToInstallation>>['data'];
type GetPaginationData<Data> = Data extends { total_count: number }
  ? Data extends { url: any }
    ? Data
    : Data[Exclude<
        keyof Data,
        "repository_selection" | "total_count" | "incomplete_results"
      >]
  : Data;
type PaginationDataResult = GetPaginationData<Data>;

Simply adding this code to the definitions should help with these situations.

wolfy1339 avatar Aug 15 '24 17:08 wolfy1339

:tada: This issue has been resolved in version 11.3.5 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

github-actions[bot] avatar Sep 29 '24 22:09 github-actions[bot]