Skip to content

astro-check (error): Tighten lib/blog.ts types end-to-end #576

Description

@lsr-explore

Tighten lib/blog.ts types end-to-end

Labels: types, tech-debt
Estimated PR size: ~3 files

Note

Ticket description was generated using Claude Code. Review before starting on a fix.

Note

The following issue adds support for npm run astro:check

Summary

lib/blog.ts accepts blogs? parameters with implicit any, then calls .map(b => b.data...) on them. This means downstream consumers get back loose types — blog/[slug].astro has blog inferred as {}, and blog/topics/index.astro has cat inferred as unknown. None of this fails at runtime today, but a future refactor won't get a compile-time warning when callers diverge.

astro check errors & warnings


src/lib/blog.ts:94:5 - error ts(2322): Type 'unknown[]' is not assignable to type 'string[]'.
  Type 'unknown' is not assignable to type 'string'.

94     topics,
       ~~~~~~
src/lib/blog.ts:21:69 - error ts(2769): No overload matches this call.
  Overload 1 of 2, '(entries: ReferenceContentEntry<never, never>[]): Promise<never[]>', gave the following error.
    Argument of type '{ id: unknown; collection: string; }[]' is not assignable to parameter of type 'ReferenceContentEntry<never, never>[]'.
      Property 'slug' is missing in type '{ id: unknown; collection: string; }' but required in type 'ReferenceContentEntry<never, never>'.
  Overload 2 of 2, '(entries: ReferenceDataEntry<keyof DataEntryMap, string>[]): Promise<({ id: string; body?: string | undefined; collection: "staff"; data: { name: { first: string; middle?: string | undefined; last?: string | undefined; }; ... 4 more ...; cited?: { ...; } | undefined; }; rendered?: RenderedContent | undefined; filePath?: string | undefined; } | ... 12 more ... | { ...; })[]>', gave the following error.
    Argument of type '{ id: unknown; collection: string; }[]' is not assignable to parameter of type 'ReferenceDataEntry<keyof DataEntryMap, string>[]'.
      Type '{ id: unknown; collection: string; }' is not assignable to type 'ReferenceDataEntry<keyof DataEntryMap, string>'.
        Types of property 'collection' are incompatible.
          Type 'string' is not assignable to type 'keyof DataEntryMap'.

21   const authors: Array<CollectionEntry<"staff">> = await getEntries(authorRefs);
                                                                       ~~~~~~~~~~
src/lib/blog.ts:84:38 - warning ts(7044): Parameter 'blogs' implicitly has an 'any' type, but a better type may be inferred from usage.

84 export async function getBlogCatalog(blogs?): Promise<BlogCatalog> {
                                        ~~~~~~
src/lib/blog.ts:71:37 - warning ts(7044): Parameter 'blogs' implicitly has an 'any' type, but a better type may be inferred from usage.

71 export async function getMostRecent(blogs?) {
                                       ~~~~~~
src/lib/blog.ts:59:37 - warning ts(7044): Parameter 'blogs' implicitly has an 'any' type, but a better type may be inferred from usage.

59 export async function orderByRecent(blogs?) {
                                       ~~~~~~
src/lib/blog.ts:37:28 - warning ts(7044): Parameter 'blog' implicitly has an 'any' type, but a better type may be inferred from usage.

37   const dates = blogs.map((blog) => ({
                              ~~~~
src/lib/blog.ts:33:36 - warning ts(7044): Parameter 'blogs' implicitly has an 'any' type, but a better type may be inferred from usage.

33 export async function getBlogDates(blogs?) {
                                      ~~~~~~
src/lib/blog.ts:28:41 - warning ts(7044): Parameter 'blog' implicitly has an 'any' type, but a better type may be inferred from usage.

28   const topics = [...new Set(blogs.map((blog) => blog.data.tags).flat())];
                                           ~~~~
src/lib/blog.ts:25:37 - warning ts(7044): Parameter 'blogs' implicitly has an 'any' type, but a better type may be inferred from usage.

25 export async function getBlogTopics(blogs?) {
                                       ~~~~~~
src/lib/blog.ts:16:44 - warning ts(7044): Parameter 'b' implicitly has an 'any' type, but a better type may be inferred from usage.

16   const authorIDs = [...new Set(blogs.map((b) => b.data.author.id).flat())];
                                              ~
src/lib/blog.ts:11:3 - warning ts(7044): Parameter 'blogs' implicitly has an 'any' type, but a better type may be inferred from usage.

11   blogs?,

Suggested fix

In src/lib/blog.ts:

  1. Type each blogs? parameter as CollectionEntry<"blogs">[] | undefined.
  2. Default blogs ??= await getCollection("blogs") inside the function (or take the collection name as a generic if there's reuse).
  3. Fix the getEntries(authorRefs) overload mismatch — authorRefs needs to satisfy ReferenceDataEntry<keyof DataEntryMap, string>[] (typically by mapping { collection: "staff", id: ... }).
  4. Type the topics return as string[] rather than unknown[] (likely needs [...new Set(blogs.map(b => b.data.tags).flat())] to be typed correctly via the input typing fix).

In src/pages/blog/[slug].astro:34:

  • Type blog and crumbs properly. blog should be CollectionEntry<"blogs">; crumbs should be Breadcrumb[].

In src/pages/blog/topics/index.astro:33:

  • Should be fixed automatically once getBlogTopics returns string[].

Affected files

  • src/lib/blog.ts
  • src/pages/blog/[slug].astro
  • src/pages/blog/topics/index.astro

Acceptance criteria

  • All errors and ts(7044) warnings in lib/blog.ts and the two consumer pages clear.
  • No new any casts.
  • Blog index, topic, and slug pages all still render.

Notes

This pairs naturally with issue #15 (lib/tips.ts), but they touch different files so they can ship as independent small PRs.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions