Мне нужно привести отформатированные числа string
к number
перед использованием значения в z.discriminatedUnion
. Это возможно? Вот упрощенный фрагмент кода:
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.info(brushSchema.safeParse({ brush_qty: "0" }).error); // message: "Invalid discriminator value. Expected 0 | '2' | '3'"
console.info(brushSchema.safeParse({ brush_qty: 0 })); // success
Взгляните на поле brush_qty
. Я ожидал, что он преобразует строку в число, и ожидаю, что zod примет и второй safeParse
, но это не так. Кажется, что discriminator
проверяется перед переходом к части схемы.
Если в этом случае невозможно заставить его number
, какой другой вариант, кроме discriminatedUnion
, я должен получить более или менее ту же функциональность?
Заранее спасибо!
🤔 А знаете ли вы, что...
JavaScript можно использовать для создания видеоигр, как 2D, так и 3D, с использованием библиотеки Three.js.
Сначала brushSchema
проанализируйте соответствующее свойство по z.coerce.string()
внутри z.object()
только с этим свойством. passthrough
явно разрешает другие свойства, но я считаю, что это все равно значение по умолчанию — просто чтобы прояснить поведение.
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.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
.object({ brush_qty: z.coerce.string() })
.passthrough()
.pipe(
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.info(
brushSchema.safeParse({
brush_qty: '2',
brush_type: 'THREAD',
brush_color: 'RED',
})
); // success
console.info(brushSchema.safeParse({ brush_qty: 0 })); // success
Я не думаю, что вам нужны какие-либо другие хаки в другой схеме, но если вы хотите сохранить возможность работать с плавающей запятой (например, сделать "2.2"
совпадением 2
), вы можете использовать аналогичный трюк:
const brushSchema = z
.object({
brush_qty: z.coerce.string().transform((arg) => parseInt(arg).toString()),
})
.passthrough()
.pipe(
z.discriminatedUnion('brush_qty', [
// ... etc
Это работает, сначала перенося все в строку; затем, если эта строка содержит плавающую точку, она нормализуется путем преобразования, которое анализирует ее и снова возвращает строку.