Addition of `.keyof()` breaks assignability for `ZodObjects`
See original GitHub issueHi there,
#1216 appears to break assignability of ZodObjects
in a subtle way. For example, the following worked before Zod 3.17.9, but fails in the latest Zod (3.17.10). I’m on TypeScript version 4.7.4.
declare const superset: { foo: string } & z.ZodObject<{
prop1: z.ZodString;
prop2: z.ZodNumber;
}>; // The `{ foo: string }` intersection is necessary for this to fail for some reason.
const subset: z.ZodObject<{ prop1: z.ZodString }> = superset;
// ^^^^^^ Error here
This produces the following type error:
Type '{ foo: string; } & ZodObject<{ prop1: ZodString; prop2: ZodNumber; }, "strip", ZodTypeAny, { prop1: string; prop2: number; }, { prop1: string; prop2: number; }>' is not assignable to type 'ZodObject<{ prop1: ZodString; }, "strip", ZodTypeAny, { prop1: string; }, { prop1: string; }>'.
The types returned by 'keyof()._parse(...)' are incompatible between these types.
Type 'ParseReturnType<"prop1" | "prop2">' is not assignable to type 'ParseReturnType<"prop1">'.
Type 'OK<"prop1" | "prop2">' is not assignable to type 'ParseReturnType<"prop1">'.
Type 'OK<"prop1" | "prop2">' is not assignable to type 'OK<"prop1">'.
Type '"prop1" | "prop2"' is not assignable to type '"prop1"'.
Type '"prop2"' is not assignable to type '"prop1"'.ts(2322)
The problem arises because z.ZodEnum<["prop1", "prop2"]>
is not assignable to z.ZodEnum<["prop1"]>
. This makes sense! However, I would argue that superset
should be assignable to subset
, because that aligns with TypeScript’s structural typing. In particular, in TypeScript,
interface Superset {
prop1: string;
prop2: number;
}
is assignable to
interface Subset {
prop1: string
}
As I mentioned in the comment, for some reason this error doesn’t surface unless you intersect the z.ZodObject
with a non-empty object type (i.e., { foo: string }
in the example above). As far as I can tell, this is a TypeScript quirk. I think with the addition of .keyof()
, TypeScript should be raising an error even without that intersection present. Maybe I’m missing something?
Not sure what the solution is here other than removing .keyof()
I guess. It could be replaced with z.keyOf(object: z.ZodObject)
or something else that doesn’t change the ZodObject
type? Or you could decide that this problem doesn’t matter! But a project I’m working on does lots of fun stuff with Zod and we rely on ZodObject
assignability working this way 🥲.
Thanks for reading and for the fantastic library.
P.S. I feel like somehow the new variance annotations could be used to solve this but I’m not sure how.
Issue Analytics
- State:
- Created a year ago
- Reactions:2
- Comments:5 (1 by maintainers)
Top GitHub Comments
Not stale, still an issue that prevents us from updating zod
I suppose comments don’t count as activity? This issue continues to prevent us from updating zod, so I wouldn’t consider it stale.