You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm trying to get recursive schemas working in Zod, powered by TypeScript's ability to handle self-reference inside getters. Example:
constCategory=z.object({name: z.string(),getparent(){// ^ 'parent' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.ts(7023)returnCategory.optional()}})
This would be a massive usability win for Zod and other schema/ORM libraries. None of these are able to directly represent cyclical types currently without redundant type annotations or some "scope"/"registry" concept to defer type resolution and later perform some kind of recursive substitution.
My understanding is that TypeScript is generally capable of inferring a recursive type with it's ... approach as long as there aren't any assignability constraints on the data being inferred.
consta={getself(){returna;},}
Applying any constraint breaks this capability. But in the case below, it seems potentially possible to typecheck the cyclical type against the constraint without issue.
consta={getself(){// ^ does not have a return type annotation and is referenced directly or indirectly in one of its return expressionsreturna;},}satisfies{self: any};
I think if the compiler was able to properly infer a above despite the satisfies clause, Zod could then support recursive objects in the way I'd described.
✅ Viability Checklist
This wouldn't be a breaking change in existing TypeScript/JavaScript code
This wouldn't change the runtime behavior of existing JavaScript code
This could be implemented without emitting different JS based on the types of the expressions
This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
Support inference on self-referential/cyclical data structures in more cases
📃 Motivating Example
Below is a more motivated example that I think demonstrates the same fundamental limitation I referenced earlier.
// base typeinterfaceZodType{optional: "true"|"false";output: any;}// stringinterfaceZodStringextendsZodType{optional: "false";output: string;}// objecttypeZodShape=Record<string,any>;typePrettify<T>={[KinkeyofT]: T[K]}&{};typeInferObjectType<ShapeextendsZodShape>=Prettify<{[kinkeyofShapeasShape[k]extends{optional: "true"} ? k : never]?: Shape[k]["output"];}&{[kinkeyofShapeasShape[k]extends{optional: "true"} ? never : k]: Shape[k]["output"];}>;interfaceZodObject<TextendsZodShape>extendsZodType{optional: "false";output: InferObjectType<T>;}// optionalinterfaceZodOptional<TextendsZodType>extendsZodType{optional: "true";output: T["output"]|undefined;}// factoriesdeclarefunctionobject<TextendsZodShape>(shape: T): ZodObject<T>;declarefunctionstring(): ZodString;declarefunctionoptional<TextendsZodType>(schema: T): ZodOptional<T>;// recursive type inference errorconstCategory=object({name: string(),getparent(){// ^ 'parent' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.ts(7023)returnoptional(Category);},});
💻 Use Cases
What do you want to use this for?
To support more ergonomic representations of inherently cyclical data structures (Zod schemas, database schemas, state diagrams, etc)
What shortcomings exist with current approaches?
Not possible
What workarounds are you using in the meantime?
None/not possible
The text was updated successfully, but these errors were encountered:
colinhacks
changed the title
Support cyclica type inference of self-referential data structures, when subject to some assignability constraints
Support cyclical type inference of self-referential data structures, when subject to some assignability constraints
May 4, 2025
🔍 Search Terms
cyclical, recursive, inference, self-referential, extends, schema, zod
I'm trying to get recursive schemas working in Zod, powered by TypeScript's ability to handle self-reference inside getters. Example:
This would be a massive usability win for Zod and other schema/ORM libraries. None of these are able to directly represent cyclical types currently without redundant type annotations or some "scope"/"registry" concept to defer type resolution and later perform some kind of recursive substitution.
My understanding is that TypeScript is generally capable of inferring a recursive type with it's
...
approach as long as there aren't any assignability constraints on the data being inferred.Applying any constraint breaks this capability. But in the case below, it seems potentially possible to typecheck the cyclical type against the constraint without issue.
I think if the compiler was able to properly infer
a
above despite thesatisfies
clause, Zod could then support recursive objects in the way I'd described.✅ Viability Checklist
⭐ Suggestion
Support inference on self-referential/cyclical data structures in more cases
📃 Motivating Example
Below is a more motivated example that I think demonstrates the same fundamental limitation I referenced earlier.
💻 Use Cases
To support more ergonomic representations of inherently cyclical data structures (Zod schemas, database schemas, state diagrams, etc)
Not possible
None/not possible
The text was updated successfully, but these errors were encountered: