You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Astro内容集合中如何创建嵌套子类型并复用?

问题:在AstroJS中为内容集合的嵌套对象创建可复用TypeScript类型

我在AstroJS中创建了一个内容集合,其Schema包含嵌套对象数组属性observations。希望为该嵌套对象创建TypeScript类型,并在组件Props中复用,同时希望直接在MDX的Frontmatter中维护这些嵌套数据,而非单独存到其他文件/集合。

现有集合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(),
    }),
});

期望在组件Props中复用类型:

<Cards observations={frontmatter.observations} />

目标Props定义:

export interface Props {
  observations: Observation[];
}

MDX Frontmatter示例:

---
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"
---

解决方案

1. 抽离嵌套对象的Zod Schema

先把observations元素的Schema抽成可复用的逻辑,确保能在集合Schema中使用Astro提供的image验证器:

// src/content/config.ts
import { defineCollection, z } from 'astro:content';

// 封装生成Observation Schema的函数,接收Astro的image验证器
const createObservationSchema = (imageValidator: ReturnType<typeof z.string>) => 
  z.object({
    title: z.string(),
    img: imageValidator(),
    body: z.string(),
  });

const blog = defineCollection({
  schema: ({ image }) => {
    // 生成当前集合可用的Observation Schema
    const observationSchema = createObservationSchema(image);
    return z.object({
      title: z.string(),
      description: z.string(),
      publishDate: z.date(),
      observations: z.array(observationSchema).optional(),
      heroImage: image().optional(),
    });
  },
});

export const collections = { blog };

2. 提取TypeScript类型

基于集合的Schema,使用Astro自动生成的集合类型或Zod的z.infer来提取Observation类型:

// 直接在src/content/config.ts中导出类型
import type { z } from 'astro:content';
import type { createObservationSchema } from './config';

// 从封装的Schema函数中提取类型
export type Observation = z.infer<ReturnType<typeof createObservationSchema>>;

// 或者从集合的entryType中提取(更贴合集合实际类型)
type BlogPostEntry = typeof collections.blog.entryType;
export type ObservationFromCollection = NonNullable<BlogPostEntry['data']['observations']>[number];

3. 在组件Props中复用类型

现在可以在组件中导入类型,定义符合需求的Props:

// src/components/Cards.tsx
import type { Observation } from '../content/config';

export interface Props {
  // 结合集合Schema的optional配置,这里可以选择是否添加可选标记
  observations?: Observation[];
}

export default function Cards({ observations }: Props) {
  if (!observations) return null;
  
  return (
    <div className="cards-grid">
      {observations.map((item, idx) => (
        <div key={idx} className="card">
          <h3>{item.title}</h3>
          <img src={item.img} alt={item.title} />
          <p>{item.body}</p>
        </div>
      ))}
    </div>
  );
}

4. 类型校验生效

当你在MDX中传递frontmatter.observations给<Cards>组件时,TypeScript会自动校验数据结构是否符合Schema定义,确保Frontmatter中的嵌套数据类型正确。


内容的提问来源于stack exchange,提问作者ivoba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 03:22:21