Skip to content
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

Zod 2: nested transforms don't work #199

Closed
lucaspiller opened this issue Oct 26, 2020 · 3 comments
Closed

Zod 2: nested transforms don't work #199

lucaspiller opened this issue Oct 26, 2020 · 3 comments

Comments

@lucaspiller
Copy link

I'm trying to use Zod to parse data that has arrays nested in an object like this (don't blame me, from a third party :D):

const classes = {
  elements: [
    {
      students: {
        elements: [{ id: 1 }, { id: 2 }, { id: 3 }],
      },
    },
    {
      students: {
        elements: [{ id: 4 }, { id: 5 }, { id: 6 }],
      },
    },
  ],
};

I can write a parser like this, that works as expected, but there's a lot of boilerplate:

const studentSchema = z.object({
  id: z.number(),
});

const classesSchema = z.object({
  elements: z.array(
    z.object({
      students: z.object({
        elements: z.array(studentSchema),
      }),
    }),
  ),
});

classesSchema.parse(classes); // works

I wrote a helper function, that builds the array schema and uses transforms to remove it from the parsed data:

export const transformArray = <T extends z.ZodTypeAny>(childSchema: T) => {
  const schema = z.object({
    elements: z.array(childSchema),
  });

  return z.transformer(schema, z.array(childSchema), (val) => val.elements);
};

const classTransformSchema = z.object({
  students: transformArray(studentSchema),
});

classTransformSchema.parse(classes.elements[0]); // works

However if I try to use this to parse the whole object, it compiles and has the correct return type, but at runtime throws an error:

const classesTransformSchema = transformArray(classTransformSchema);

classesTransformSchema.parse(classes); // throws `invalid_type` error
  • Zod 2.0.0-beta.16
  • TypeScript 4.0.3
@colinhacks
Copy link
Owner

I agree this is quite unintuitive. I'm also not sure if this is fixable.

The problem seems to be with your implementation of transformArray. You shouldn't be allowed to implement that function in that way; it's only possible because z.ZodTypeAny is perhaps too permissive and contains lots of anys.

If you "unwrap" the top-level call to transformArray you can see the type error that Zod should have surfaced:

const transformArray = <T extends z.ZodTypeAny>(childSchema: T) => {
  const schema = z.object({
    elements: z.array(childSchema),
  });

  return z.transformer(schema, z.array(childSchema), val => {
    return val.elements;
  });
};

const classSchema = z.object({
  students: transformArray(
    z.object({
      id: z.number(),
    }),
  ),
});

const classesSchema = z.transformer(
  z.object({ elements: z.array(classSchema) }),
  z.array(classSchema),
  val => {
    return val.elements;
  },
);
Argument of type '(val: { elements: { students: { id: number; }[]; }[]; }) => { students: { id: number; }[]; }[]' is not assignable to parameter of type '(arg: { elements: { students: { id: number; }[]; }[]; }) => { students: { elements: { id: number; }[]; }; }[] | Promise<{ students: { elements: { id: number; }[]; }; }[]>'.
  Type '{ students: { id: number; }[]; }[]' is not assignable to type '{ students: { elements: { id: number; }[]; }; }[] | Promise<{ students: { elements: { id: number; }[]; }; }[]>'.
    Type '{ students: { id: number; }[]; }[]' is not assignable to type '{ students: { elements: { id: number; }[]; }; }[]'.
      Type '{ students: { id: number; }[]; }' is not assignable to type '{ students: { elements: { id: number; }[]; }; }'.
        Types of property 'students' are incompatible.
          Property 'elements' is missing in type '{ id: number; }[]' but required in type '{ elements: { id: number; }[]; }'.

This is definitely a major issue with how transformers are currently implemented. I'll keep thinking about this one.

@lucaspiller
Copy link
Author

Thanks 👍

@colinhacks colinhacks changed the title Zod2: Nested transform don't work Zod 2: nested transforms don't work Oct 29, 2020
@colinhacks
Copy link
Owner

There's not technically a bug here so I'm gonna close. You've just got to be careful when using generics and transformers together.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants