Как создать отдельную схему для «черновиков» и «опубликованных» сообщений и как заставить 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.
);
Является ли это «ожидаемым» способом работы со схемами или я упускаю что-то важное?