Есть ли способ получить массив объектов с некоторыми из них литералами?

Я думаю о следующей проверке с помощью zod, и я понятия не имею, как это сделать (или, если это возможно, с помощью zod). Мне нужен массив объектов, все одинаковой формы, с некоторыми из них с буквальными реквизитами, мне нужно, чтобы они всегда присутствовали в массиве.

Пример: мне всегда нужны в массиве объекты с именами required1 и required2, а затем другие дополнительные объекты, имеющие такую ​​же форму.

      [
    {
      name: z.literal('required1'),
      otherprop: z.number()
    },
    {
      name: z.literal('required2'),
      otherprop: z.number()
    },
    // I want to include one or more of the following too (optionals).
    {
      name: z.string(),
      otherprop: z.number()
    },
]

Этот другой пример нужно выбросить, потому что отсутствует required2

      [
    {
      name: z.literal('required1'),
      otherprop: z.number()
    },
    // I want to include one or more of the following too.
    {
      name: z.string(),
      otherprop: z.number()
    },
]

Есть подсказка?

1 ответ

Решение

Невозможно решить проблему, используя только систему набора текста. Решил проблему методом от Zod. Я выложу две версии, одну попроще с refine и другие более сложные с superRefine.

Базовый код

      const elementSchema = z.object({
  name: z.string(),
  otherprop: z.number(),
})
type Element = z.infer<typeof elementSchema>;

// In my real code, here I have a function that returns the array of required names for the case.
const names = ['required1', 'required2'];

function refineNames(elements: Element[]): boolean {
       return names.every((el: string) => elements.some(x => x.name === el));
}

Простой способ с помощью всего лишь уточнения

      z.array(elementSchema).refine(
  (elements) => refineNames(elements),
  { message: `There are missing names. Required names are ${names.join(', ')}`, }
);

Сложный способ с использованием superRefine. Но мы можем сравнить также и на наличие повторяющихся записей.

      function hasDuplicates(elements: Element[]): boolean {
    const names = elements.map(e => e.name);

    return names.length !== new Set(names).size;
}

z.array(elementSchema).superRefine((elements, ctx) => {
        if (refineNames(elements)) {
            ctx.addIssue({
                code: z.ZodIssueCode.custom,
                message: `There are missing names. Required names are ${names.join(', ')}`,
            });
        }

        if (hasDuplicates(elements)) {
            ctx.addIssue({
                code: z.ZodIssueCode.custom,
                message: 'No duplicated name allowed.',
            });
        }
    }),

Использованная литература:

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