Как создать отдельную схему для «черновиков» и «опубликованных» сообщений и как заставить TypeScript легко различать их (коллекции контента Astro v2)

Я пытаюсь настроитьContent Collectionsдля моего блога в Astro . Почти сразу я столкнулся с проблемами с черновиками постов: в них отсутствовали некоторые поля схемы, и Зоду это не нравилось.

Копаясь в документах Зода , я придумал , так что схема для «черновиков» будет намного свободнее, чем для опубликованных постов:

      // src/content/config.ts
// (simplified example)

const publishedPostSchema = z.object({
  title: z.string(),
  author: z.enum(["John Doe", "Jane Doe"]),
  dateCreated: z.string().transform((str) => new Date(str)),
  description: z.string(),
  draft: z.literal(null),
});

const draftPostSchema = z.object({
  title: z.string().nullable(),
  author: z.enum(["John Doe", "Jane Doe"]).nullable(),
  dateCreated: z
    .string()
    .transform((str) => new Date(str))
    .nullable(),
  draft: z.literal(true),
});

const exampleBlogCollection = defineCollection({
  schema: z.discriminatedUnion("draft", [publishedPostSchema, draftPostSchema]),
});

export const collections = {
  blog: exampleBlogCollection,
};

Это работает, но у меня все еще есть две небольшие проблемы:

 1. Это заставляет меня иметь буквальное поле «черновик» для всех опубликованных сообщений. я бы предпочел включитьnull,falseиundefinedценности, ноz.discriminatedUnionпринимает только литералы в дискриминационном поле. Есть ли обходной путь?

 2. Результирующий тип представляет собой размеченное объединение, но все еще требуется много работы, чтобы гарантировать, что инструментарий TypeScript, что то, что я передаю, не может принимать значение NULL:

Это не работает (ошибки TypeScript):

      const allPosts = await getCollection('blog')

const publishedPosts = rawPosts.filter(post => post.data.draft === null)

publishedPosts .sort(
  (a, b) =>
    +(b.data.dateCreated) - +(a.data.dateCreated) // TS error: `dateCreated` can be `null`…
);

Это работает, но… это довольно многословно:

      const allPosts = await getCollection('blog')

type PublishedPost = CollectionEntry<"blog"> & { data: { draft: null }}


function isPublishedPost(post: typeof allPosts[number]): post is PublishedPost {
    return post.data.draft === null
}

const publishedPosts = allPosts.filter(isPublishedPost)

publishedPosts .sort(
  (a, b) =>
    +(b.data.dateCreated) - +(a.data.dateCreated) // O.K.
);

Является ли это «ожидаемым» способом работы со схемами или я упускаю что-то важное?

0 ответов

Другие вопросы по тегам