zod: `z.ZodType` and `refine` not working as expected
Consider the following code:
const stringIsValid = (value: string): value is "a" | "b" =>
  ["a", "b"].includes(value);
const ASchema = z.object({
  type: z.string().refine(stringIsValid),
});
type A = z.infer<typeof ASchema>;
interface B {
  id: string;
  children: (z.infer<typeof ASchema> | B)[];
}
const BSchema: z.ZodType<B> = z.lazy(() =>
  z.object({
    id: z.string(),
    children: z.array(z.union([ASchema, BSchema])),
  })
);
type A is correctly inferred as:
{
    type: "a" | "b";
}
But when creating the BSchema, and assigning it to z.ZodType<B> I get the following error:
Type 'ZodLazy<ZodObject<{ id: ZodString; children: ZodArray<ZodUnion<[ZodObject<{ type: ZodEffects<ZodString, "a" | "b", string>; }, "strip", ZodTypeAny, { type: "a" | "b"; }, { ...; }>, ZodType<...>]>, "many">; }, "strip", ZodTypeAny, { ...; }, { ...; }>>' is not assignable to type 'ZodType<B, ZodTypeDef, B>'.
  The types of '_input.children' are incompatible between these types.
    Type '({ type: string; } | B)[]' is not assignable to type '({ type: "a" | "b"; } | B)[]'.
      Type '{ type: string; } | B' is not assignable to type '{ type: "a" | "b"; } | B'.
        Type '{ type: string; }' is not assignable to type '{ type: "a" | "b"; } | B'.
          Type '{ type: string; }' is not assignable to type '{ type: "a" | "b"; }'.
            Types of property 'type' are incompatible.
              Type 'string' is not assignable to type '"a" | "b"'
Is this a bug or am I doing something weird? Zod-version is 3.20.2 and typescript version is 4.8.4
About this issue
- Original URL
 - State: closed
 - Created a year ago
 - Comments: 24 (8 by maintainers)
 
Thanks for the help, it solve my issue (funny that i found it almost the same day as you).
I didn’t known that you could/should specify input type in this situation.
Adding an example in the docs would be a good thing
After some investigations, I realized I misunderstood some things, here is the proper way to solve the problem that @JoelBeeldi had!
Apparently, you need to define the “Input”-type of the schema, if you use
refine/transformwhich is passed as the third type argument. Something we maybe should add to the docs. Might submit a PR for that another time!Username too and thanks for the maintenance of this awesome lib
Username! Thanks
Nice! Thanks for your support @JacobWeisenburger ❤️
I understand now. I think I missed “would” when I read what you said.
I agree that this is something that should work without type casting or assertions.