diff options
author | 2023-08-28 18:02:05 +0200 | |
---|---|---|
committer | 2023-08-28 12:02:05 -0400 | |
commit | ffc9e2d3de46049bf3d82140ef018f524fb03187 (patch) | |
tree | 363caa2c23bd5771a003748215704ec40461c47a | |
parent | 57e9a28063c28e5ad81034ca170291aba6084100 (diff) | |
download | astro-ffc9e2d3de46049bf3d82140ef018f524fb03187.tar.gz astro-ffc9e2d3de46049bf3d82140ef018f524fb03187.tar.zst astro-ffc9e2d3de46049bf3d82140ef018f524fb03187.zip |
feat(paginate): Return exact types from paginate() (#8229)
* feat(paginate): Return exact types from paginate()
* chore: changeset
* fix(types): Fix infer utils while I'm here
---------
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
-rw-r--r-- | .changeset/shiny-dryers-swim.md | 5 | ||||
-rw-r--r-- | packages/astro/client.d.ts | 2 | ||||
-rw-r--r-- | packages/astro/src/@types/astro.ts | 42 | ||||
-rw-r--r-- | packages/astro/src/core/render/paginate.ts | 12 | ||||
-rw-r--r-- | packages/astro/src/core/render/route-cache.ts | 5 |
5 files changed, 53 insertions, 13 deletions
diff --git a/.changeset/shiny-dryers-swim.md b/.changeset/shiny-dryers-swim.md new file mode 100644 index 000000000..f943b2180 --- /dev/null +++ b/.changeset/shiny-dryers-swim.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Paginate will now return exact types instead of a naive Record diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts index e6389d415..9d064c0b1 100644 --- a/packages/astro/client.d.ts +++ b/packages/astro/client.d.ts @@ -57,7 +57,7 @@ declare module 'astro:assets' { }; type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] }; - type Simplify<T> = { [KeyType in keyof T]: T[KeyType] }; + type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {}; type ImgAttributes = WithRequired< Omit<import('./types').HTMLAttributes<'img'>, 'src' | 'width' | 'height'>, 'alt' diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index bc47e0779..3efbb7ae8 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1600,7 +1600,9 @@ export type GetStaticPaths = ( * const { slug } = Astro.params as Params; * ``` */ -export type InferGetStaticParamsType<T> = T extends () => infer R | Promise<infer R> +export type InferGetStaticParamsType<T> = T extends ( + opts?: GetStaticPathsOptions +) => infer R | Promise<infer R> ? R extends Array<infer U> ? U extends { params: infer P } ? P @@ -1631,7 +1633,9 @@ export type InferGetStaticParamsType<T> = T extends () => infer R | Promise<infe * const { propA, propB } = Astro.props; * ``` */ -export type InferGetStaticPropsType<T> = T extends () => infer R | Promise<infer R> +export type InferGetStaticPropsType<T> = T extends ( + opts: GetStaticPathsOptions +) => infer R | Promise<infer R> ? R extends Array<infer U> ? U extends { props: infer P } ? P @@ -1678,13 +1682,13 @@ export type MarkdownContent<T extends Record<string, any> = Record<string, any>> * * [Astro reference](https://docs.astro.build/en/reference/api-reference/#paginate) */ -export interface PaginateOptions { +export interface PaginateOptions<PaginateProps extends Props, PaginateParams extends Params> { /** the number of items per-page (default: `10`) */ pageSize?: number; /** key: value object of page params (ex: `{ tag: 'javascript' }`) */ - params?: Params; + params?: PaginateParams; /** object of props to forward to `page` result */ - props?: Props; + props?: PaginateProps; } /** @@ -1718,7 +1722,33 @@ export interface Page<T = any> { }; } -export type PaginateFunction = (data: any[], args?: PaginateOptions) => GetStaticPathsResult; +type OmitIndexSignature<ObjectType> = { + // eslint-disable-next-line @typescript-eslint/ban-types + [KeyType in keyof ObjectType as {} extends Record<KeyType, unknown> + ? never + : KeyType]: ObjectType[KeyType]; +}; +// eslint-disable-next-line @typescript-eslint/ban-types +type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {}; +export type PaginateFunction = < + PaginateData, + AdditionalPaginateProps extends Props, + AdditionalPaginateParams extends Params, +>( + data: PaginateData[], + args?: PaginateOptions<AdditionalPaginateProps, AdditionalPaginateParams> +) => { + params: Simplify< + { + page: string | undefined; + } & OmitIndexSignature<AdditionalPaginateParams> + >; + props: Simplify< + { + page: Page<PaginateData>; + } & OmitIndexSignature<AdditionalPaginateProps> + >; +}[]; export type Params = Record<string, string | undefined>; diff --git a/packages/astro/src/core/render/paginate.ts b/packages/astro/src/core/render/paginate.ts index dffabe178..f8cd8709d 100644 --- a/packages/astro/src/core/render/paginate.ts +++ b/packages/astro/src/core/render/paginate.ts @@ -1,18 +1,20 @@ import type { - GetStaticPathsResult, Page, PaginateFunction, + PaginateOptions, Params, Props, RouteData, } from '../../@types/astro'; import { AstroError, AstroErrorData } from '../errors/index.js'; -export function generatePaginateFunction(routeMatch: RouteData): PaginateFunction { +export function generatePaginateFunction( + routeMatch: RouteData +): (...args: Parameters<PaginateFunction>) => ReturnType<PaginateFunction> { return function paginateUtility( data: any[], - args: { pageSize?: number; params?: Params; props?: Props } = {} - ) { + args: PaginateOptions<Props, Params> = {} + ): ReturnType<PaginateFunction> { let { pageSize: _pageSize, params: _params, props: _props } = args; const pageSize = _pageSize || 10; const paramName = 'page'; @@ -31,7 +33,7 @@ export function generatePaginateFunction(routeMatch: RouteData): PaginateFunctio } const lastPage = Math.max(1, Math.ceil(data.length / pageSize)); - const result: GetStaticPathsResult = [...Array(lastPage).keys()].map((num) => { + const result = [...Array(lastPage).keys()].map((num) => { const pageNum = num + 1; const start = pageSize === Infinity ? 0 : (pageNum - 1) * pageSize; // currentPage is 1-indexed const end = Math.min(start + pageSize, data.length); diff --git a/packages/astro/src/core/render/route-cache.ts b/packages/astro/src/core/render/route-cache.ts index f607cf5d9..d43ce514b 100644 --- a/packages/astro/src/core/render/route-cache.ts +++ b/packages/astro/src/core/render/route-cache.ts @@ -3,6 +3,7 @@ import type { GetStaticPathsItem, GetStaticPathsResult, GetStaticPathsResultKeyed, + PaginateFunction, Params, RouteData, RuntimeMode, @@ -50,7 +51,9 @@ export async function callGetStaticPaths({ // Calculate your static paths. let staticPaths: GetStaticPathsResult = []; staticPaths = await mod.getStaticPaths({ - paginate: generatePaginateFunction(route), + // Q: Why the cast? + // A: So users downstream can have nicer typings, we have to make some sacrifice in our internal typings, which necessitate a cast here + paginate: generatePaginateFunction(route) as PaginateFunction, rss() { throw new AstroError(AstroErrorData.GetStaticPathsRemovedRSSHelper); }, |