Можно ли предварительно обработать дискриминатор в дискриминируемом объединении zod?

Мне нужно привести отформатированные числа 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, я должен получить более или менее ту же функциональность?

Заранее спасибо!

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сначала 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

Это работает, сначала перенося все в строку; затем, если эта строка содержит плавающую точку, она нормализуется путем преобразования, которое анализирует ее и снова возвращает строку.

Спасибо! coerce, passthrough и pipe немного подчистят мои схемы! Это именно то, чего я пытался достичь.

slinden 30.06.2024 16:26

Другие вопросы по теме

Похожие вопросы

Лучшая практика асинхронного получения данных API из разных конечных точек с помощью React?
Где хранятся анонимные функции обратного вызова для setTimeout?
Добавить числа в объект в массиве JavasScript из индекса ниже значения и возвращаемого значения
Печать и предварительный просмотр веб-страницы не работают должным образом в браузере Microsoft Edge
Возврат значений на страницу Razor — запутанный Javascript или .cs?
Сборка npm run не удалась из-за несовместимости машинописного текста или lodash
TypeScript «Нет перегрузки, соответствующей этому вызову»
Способ определения точных свойств стиля, которые в данный момент применяются веб-анимацией (без смешивания со всеми применяемыми в данный момент стилями)
Как загрузить изображение на холст в Gradio с помощью специального HTML и JavaScript?
Dash.js извлекает файлы .m4s при настройке video.currentTime и приводит к ошибкам. Ошибки при настройке video.currentTime в Dash.js