Can't use discriminatedUnion after transform
#2100
-
I'm building a federated social media app (think like Mastodon) which validates external json data in ActivityStreams format. There are various competing ways to implement a quote post, for example. I want to consolidate them into one: const noteSchema = z.object({
type: z.literal('Note'),
id: apId,
to: recipients,
cc: recipients,
content: z.string(),
attachment: z.array(attachmentSchema).optional().catch(undefined),
inReplyTo: apId.optional(),
attributedTo: apId,
published: published(),
// Quote posting
quoteUrl: apId.optional(),
quoteURL: apId.optional(),
quoteUri: apId.optional(),
_misskey_quote: apId.optional(),
}).transform((note) => {
const { quoteUrl, quoteUri, quoteURL, _misskey_quote, ...rest } = note;
return {
// Consolidate the quote into one field
quoteUrl: quoteUrl || quoteUri || quoteURL || _misskey_quote,
...rest,
}
}); This mostly works, but since I've tried accessing Is there a better way to do what I'm trying to do with Zod? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
Is this what you are looking for? const noteSchema = z.object( {
type: z.literal( 'Note' ),
id: apId,
to: recipients,
cc: recipients,
content: z.string(),
attachment: z.array( attachmentSchema ).optional().catch( undefined ),
inReplyTo: apId.optional(),
attributedTo: apId,
published: published(),
quoteUrl: apId.optional(),
} )
const flexibleNoteSchema = noteSchema.extend( {
quoteURL: apId.optional(),
quoteUri: apId.optional(),
_misskey_quote: apId.optional(),
} ).transform( ( note ) => {
const { quoteUrl, quoteUri, quoteURL, _misskey_quote, ...rest } = note
return {
quoteUrl: quoteUrl || quoteUri || quoteURL || _misskey_quote,
...rest,
}
} )
const objectSchema = z.union( [
flexibleNoteSchema,
actorSchema,
] ).pipe(
z.discriminatedUnion( 'type', [
noteSchema,
actorSchema,
] )
) If you found my answer satisfactory, please consider supporting me. Even a small amount is greatly appreciated. Thanks friend! 🙏 |
Beta Was this translation helpful? Give feedback.
-
For anyone else finding this issue, this is a limitation of zod at least until v4 #2441 (comment) The accepted answer is a valid workaround, but I have the hunch that it throws the advantage of using An alternative, that might be more efficient could be const noteSchema = z.object( {
type: z.literal( 'Note' ),
id: apId,
to: recipients,
cc: recipients,
content: z.string(),
attachment: z.array( attachmentSchema ).optional().catch( undefined ),
inReplyTo: apId.optional(),
attributedTo: apId,
published: published(),
quoteUrl: apId.optional(),
} );
const objectSchema = z.discriminatedUnion( 'type', [
noteSchema,
actorSchema,
])
.transform((val) =>
val.type === 'Note'
// put the transforms after the switch
? ({...val, quoteUrl: quoteUrl || quoteUri || quoteURL || _misskey_quote})
: val
) (Or just use |
Beta Was this translation helpful? Give feedback.
Is this what you are looking for?