Is it possible to preprocess discriminator in zod discriminated union?

I need to coerce string formatted numbers to number before using a value in z.discriminatedUnion. Is this possible? Here is a simplified code snippet:

import { z } from "zod";

const BrushColorEnum = z.enum(
  ["BLUE_SILVER", "GREEN_SILVER", "RED", "GREEN_BLACK"],
  { message: "Invalid option" }
);

const BrushTypeEnum = z.enum(["THREAD", "MIXED", "CARLITE"], {
  message: "Invalid option",
});

const noBrushSchema = z.object({
  brush_qty: z.preprocess(
    (val) => (typeof val === "string" ? parseInt(val, 10) : val),
    z.literal(0)
  ),
  brush_type: z
    .union([
      z.string().length(0, { message: "Invalid option" }),
      z.undefined(),
      z.literal(false),
    ])
    .transform(() => undefined),
  brush_color: z
    .union([
      z.string().length(0, { message: "Invalid option" }),
      z.undefined(),
      z.literal(false),
    ])
    .transform(() => undefined),
});

const brushSchema = z.discriminatedUnion("brush_qty", [
  noBrushSchema,
  z.object({
    brush_qty: z.literal("2"),
    brush_type: BrushTypeEnum,
    brush_color: BrushColorEnum,
  }),
  z.object({
    brush_qty: z.literal("3"),
    brush_type: BrushTypeEnum,
    brush_color: BrushColorEnum,
  }),
]);

console.log(brushSchema.safeParse({ brush_qty: "0" }).error); // message: "Invalid discriminator value. Expected 0 | '2' | '3'"
console.log(brushSchema.safeParse({ brush_qty: 0 })); // success

Take a look at the brush_qty field. I would expect it to transform the string to number and I expect zod accept also the second safeParse, but it doesn’t. It seems that the discriminator get validated before passing on to the schema part.

If in this case it is impossible to coerce it to number, what other choices than discriminatedUnion I have to get more or less the same functionality?

Thanks in advance!