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
相关产品推荐
相关产品推荐

