Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Support cyclical type inference of self-referential data structures, when subject to some assignability constraints #61659

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
6 tasks done
colinhacks opened this issue May 4, 2025 · 1 comment Β· May be fixed by #61660
Open
6 tasks done
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone

Comments

@colinhacks
Copy link

colinhacks commented 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:

const Category = z.object({
  name: z.string(),
  get parent(){
    // ^ '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)
    return Category.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.

const a = {
  get self() {
    return a;
  },
}

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.

const a = {
  get self() {
  //  ^ does not have a return type annotation and is referenced directly or indirectly in one of its return expressions
    return a;
  },
} 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

⭐ 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.

// base type
interface ZodType {
  optional: "true" | "false";
  output: any;
}

// string
interface ZodString extends ZodType {
  optional: "false";
  output: string;
}

// object
type ZodShape = Record<string, any>;
type Prettify<T> = { [K in keyof T]: T[K] } & {};
type InferObjectType<Shape extends ZodShape> = Prettify<
  {
    [k in keyof Shape as Shape[k] extends { optional: "true" } ? k : never]?: Shape[k]["output"];
  } & {
    [k in keyof Shape as Shape[k] extends { optional: "true" } ? never : k]: Shape[k]["output"];
  }
>;
interface ZodObject<T extends ZodShape> extends ZodType {
  optional: "false";
  output: InferObjectType<T>;
}

// optional
interface ZodOptional<T extends ZodType> extends ZodType {
  optional: "true";
  output: T["output"] | undefined;
}

// factories
declare function object<T extends ZodShape>(shape: T): ZodObject<T>;
declare function string(): ZodString;
declare function optional<T extends ZodType>(schema: T): ZodOptional<T>;

// recursive type inference error
const Category = object({
  name: string(),
  get parent() {
      // ^ '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)
    return optional(Category);
  },
});

πŸ’» Use Cases

  1. 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)

  1. What shortcomings exist with current approaches?

Not possible

  1. What workarounds are you using in the meantime?

None/not possible

@colinhacks 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
@Andarist
Copy link
Contributor

Andarist commented May 5, 2025

A funny thing here is that reading from your type here somehow "fixes" the issue: TS playground

But that "trick" doesn't quite solve the simplified satisfies-based example.

@RyanCavanaugh RyanCavanaugh added Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases labels May 6, 2025
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone May 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants