v4: z.interface() not suport jsDoc
I noticed an issue where JSDoc comments, such as @deprecated, are not preserved after using z.infer on z.interface(), while they are correctly retained when using z.object().
📷 Screenshot
In the screenshot below, you can see that the @deprecated annotation appears in the inferred type from z.object(), but not from z.interface():
🧪 Reproduction
import * as z from 'zod';
const interfaceSchema = z.interface({
/**
* hellow value
*
* @deprecated
*/
hellow: z.string()
});
const objectSchema = z.object({
/**
* hellow value
*
* @deprecated
*/
hellow: z.string()
});
type ZInterface = z.infer<typeof interfaceSchema>;
const zInterface: ZInterface = { hellow: 'hellow' };
zInterface.hellow
type ZObject = z.infer<typeof objectSchema>;
const zObject: ZObject = { hellow: 'hellow' };
zObject.hellow
🧠 Expected Behavior
I expected z.infer<typeof interfaceSchema> to retain JSDoc metadata like @deprecated, just like z.object() does.
How about adding a method .deprecated() and adding the schema to the metadata?
https://json-schema.org/draft/2020-12/json-schema-validation#section-9.3
@PandaWorker
That might be good in some cases, but not for mine — I should've included my use case in the first comment.
In my use case, I rely on z.infer to define my DTOs, so I can avoid duplicating type definitions and keep validation logic decoupled from TypeScript interfaces.
However, when JSDoc annotations (not just @deprecated, but any comments) are lost in the inferred type, I’m forced to manually define a separate TypeScript interface just to preserve documentation metadata — which defeats part of the purpose of using z.infer.
Additionally, if z.object could support getters for defining cyclical properties, that would be great. But I’m not sure whether using getters is what causes the JSDoc loss or not.
I would wager it's the optional key behaviour that strips the JSDoc
@samchungy
Yes, you're right. But I've found that any type inference or transformation causes JSDoc to be lost, including:
z.interface()z.any().optional()
At this point, I believe this isn't a bug in Zod per se — it's a TypeScript limitation.
Here’s a minimal example:
const original = {
/** user id */
id: true,
} as const;
type Original = typeof original;
const transformed = {
get id() {
return original.id;
},
};
transformed.id; // JSDoc lost
const typeInfer = () => original;
typeInfer().id; // JSDoc lost
It might be helpful if Zod exposes something like an originalShape property — so that others who want to build a CLI tool or a TypeDoc plugin to work around this limitation can still access the original input object, where the JSDoc annotations are preserved.
z.interface() has been removed since this issue was open. z.object() continues to support JSDoc.