Astro: Dynamic routes with params and pagination
The internet is replete with examples of creating dynamic routes using Astro. Look for paginated routes with parameters and Typescript, however, and the results all seem a little incomplete. For a beginner like I am, it wasn’t entirely clear how the different examples in the documentation work together. So let’s walk through this.
Dissecting getStaticPaths
I think the first thing that was slightly confusing for me was that non-paginated routes look like this for example:
However, according to Astro’s Routing Reference, this is what paginated routes look like:
Slightly altered from Astro’s Routing Reference
First, note the change in structure from the posts being passed as props to being a direct argument of paginate. It would have been more clear if it still passes through props, maybe with a predetermined property name, and whereas maybe pageSize becomes a direct argument in my opinion.
Second, despite this being the latest version of the docs, the example uses outdated constructs like import.meta.glob. It also avoids any Typescript typing (that exists from prior examples from the same page), which begs the question whether e.g. satisfies GetStaticPaths is even compatible with pagination. I’m happy to report that it is, and the example in the documentation is just outdated.
Some pitfalls
Of particular, I had a question of why flatMap is necessary, since it seems like a single object is being returned. But upon closer inspection, the paginate function actually wraps each single result with an array. I found this to be a pitfall, since it was unintuitive why that would be the case.
Continuing on, Typescript Configuration in Astro’s docs suggests to infer getStaticPaths() types.
Slightly altered from Astro’s Typescript Configuration
Strangely, I found that the params inference always returned “never” types instead of “string” as it should. Additionally, VSCode reports correct inference of the props type even without InferGetStaticPropsType.
It seems visually odd that it isn’t const {page} = Astro.props as Props, but adding this causes the component to silently fail to recognize the prop, even though the prop clearly has been passed in, which could be confirmed with a console.log(page); statement.
In the end, I find that the following works just as well, if not better.