From 83828f3c2d9dedad4ea1b3bd53e7313adf716f96 Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Mon, 26 Aug 2024 11:17:21 -0400 Subject: [PATCH 1/2] fix: dirty union bug bug repro: https://stackblitz.com/edit/stackblitz-starters-swdj3e?file=index.test.js&startScript=test --- src/__tests__/unions.test.ts | 20 ++++++++++++++++++++ src/types.ts | 9 --------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/__tests__/unions.test.ts b/src/__tests__/unions.test.ts index e7b30bcef..8713293ff 100644 --- a/src/__tests__/unions.test.ts +++ b/src/__tests__/unions.test.ts @@ -62,3 +62,23 @@ test("readonly union", async () => { union.parse("asdf"); union.parse(12); }); + +test("union of strict objects", async () => { + // ensure bug in 3.23.8 is fixed, where "dirty" parse failures would mean reporting the first error, rather than a proper `invalid_union` with `unionErrors`. + // Demo of bug: https://stackblitz.com/edit/stackblitz-starters-swdj3e?file=index.test.js&startScript=test + const union = z.union([ + z.object({ x: z.number() }).strict(), // + z.object({ y: z.number() }).strict(), + ]); + expect(union.safeParse({ x: 1, y: 1 })).toMatchObject({ + success: false, + error: { + issues: [ + { + code: "invalid_union", + unionErrors: [expect.any(z.ZodError), expect.any(z.ZodError)], + }, + ], + }, + }); +}); diff --git a/src/types.ts b/src/types.ts index 0767073c5..ad17aefaf 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2987,8 +2987,6 @@ export class ZodUnion extends ZodType< }) ).then(handleResults); } else { - let dirty: undefined | { result: DIRTY; ctx: ParseContext } = - undefined; const issues: ZodIssue[][] = []; for (const option of options) { const childCtx: ParseContext = { @@ -3007,8 +3005,6 @@ export class ZodUnion extends ZodType< if (result.status === "valid") { return result; - } else if (result.status === "dirty" && !dirty) { - dirty = { result, ctx: childCtx }; } if (childCtx.common.issues.length) { @@ -3016,11 +3012,6 @@ export class ZodUnion extends ZodType< } } - if (dirty) { - ctx.common.issues.push(...dirty.ctx.common.issues); - return dirty.result; - } - const unionErrors = issues.map((issues) => new ZodError(issues)); addIssueToContext(ctx, { code: ZodIssueCode.invalid_union, From 3b3af1942e23078b055089251e34828f2c7baae9 Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Tue, 27 Aug 2024 08:58:01 -0400 Subject: [PATCH 2/2] mv assertion to existing test --- src/__tests__/unions.test.ts | 42 +++++++++++++++--------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/__tests__/unions.test.ts b/src/__tests__/unions.test.ts index 8713293ff..d6d007da7 100644 --- a/src/__tests__/unions.test.ts +++ b/src/__tests__/unions.test.ts @@ -32,17 +32,29 @@ test("return valid over invalid", () => { }); }); -test("return dirty result over aborted", () => { +test("union with dirty result", () => { const result = z .union([z.number(), z.string().refine(() => false)]) .safeParse("a"); expect(result.success).toEqual(false); if (!result.success) { - expect(result.error.issues).toEqual([ + expect(result.error.issues).toMatchObject([ { - code: "custom", - message: "Invalid input", - path: [], + code: "invalid_union", + unionErrors: [ + expect.objectContaining({ + code: "invalid_type", + expected: "number", + received: "string", + path: [], + message: "Expected number, received string", + }), + expect.objectContaining({ + code: "custom", + message: "Invalid input", + path: [], + }), + ], }, ]); } @@ -62,23 +74,3 @@ test("readonly union", async () => { union.parse("asdf"); union.parse(12); }); - -test("union of strict objects", async () => { - // ensure bug in 3.23.8 is fixed, where "dirty" parse failures would mean reporting the first error, rather than a proper `invalid_union` with `unionErrors`. - // Demo of bug: https://stackblitz.com/edit/stackblitz-starters-swdj3e?file=index.test.js&startScript=test - const union = z.union([ - z.object({ x: z.number() }).strict(), // - z.object({ y: z.number() }).strict(), - ]); - expect(union.safeParse({ x: 1, y: 1 })).toMatchObject({ - success: false, - error: { - issues: [ - { - code: "invalid_union", - unionErrors: [expect.any(z.ZodError), expect.any(z.ZodError)], - }, - ], - }, - }); -});