Search code examples
astrojs

How to create sub types in Astro content collections


I have a content collection in AstroJs which has a property as an object.
How can i create a Type for this object and reuse it in a component?

The schema:

const blog = defineCollection({
  schema: ({ image }) =>
    z.object({
      title: z.string(),
      description: z.string(),
      publishDate: z.date(),
      observations: z
        .array(
          z.object({
            title: z.string(),
            img: image(),
            body: z.string(),
          })
        )
        .optional(),
      heroImage: image().optional(),
    }),
});

The element in the observations should become a Type so that i can reference it in a props Type later: F.e.:

<Cards observations={frontmatter.observations} />

Desired props definition:

export interface Props {
  observations: Observation[];
}

I tried with references as described here: https://docs.astro.build/en/guides/content-collections/#defining-collection-references.

But this requires to store the object in seperate files resp. collection.
I would like to have them in the frontmatter of the mdx file directly, like so:

---
title: "title"
description: "some desc."
publishDate: 2022-05-23
observations:
  - title: "title 1"
    img: "../../assets/img1.jpg"
    body: "text"
  - title: "title 2"
    img: "../../assets/img2.jpg"
    body: "text"
---

So how can i have a Type for this nested "observation" element?


Solution

  • Since Astro is using Zod for this, you can do:

    import { defineCollection, z, type ImageFunction } from "astro:content";
    
    const getObservationSchema = (image: ImageFunction) =>
      z.object({
        title: z.string(),
        img: image(),
        body: z.string(),
      })
    
    const blog = defineCollection({
      schema: ({ image }) =>
        z.object({
          title: z.string(),
          description: z.string(),
          publishDate: z.date(),
          observations: z.array(getObservationSchema(image)).optional(),
          heroImage: image().optional(),
        }),
    });
    
    export type Observation = z.infer<ReturnType<typeof getObservationSchema>>