Lzh on GitHub

联合(union)代表一种逻辑“或”的关系。你可以在你的模式(schema)中应用这个概念,使用 unionvariant。对于可辨识联合(discriminated unions),你使用 variant,在所有其他情况下,你使用 union

union 模式

union 模式函数可以在你以数组形式传入的任意数量的模式之间创建“或”的关系。验证时,该模式返回第一个成功验证的模式的结果。

import * as v from 'valibot';

// TypeScript
type Union = string | number;

// Valibot
const UnionSchema = v.union([v.string(), v.number()]);

如果一个错误的输入可以根据数据类型唯一地分配给其中一个模式,则返回该模式的结果。否则,会返回一个包含每个模式问题的通用问题。这是库中的一个特例,因为 union 的问题可能相互矛盾。

如果输入是 null 而不是字符串或数字,则会返回以下问题。由于在这种情况下输入无法与任一模式关联,因此两个模式的问题都会作为子问题返回。

[
  {
    kind: 'schema',
    type: 'union',
    input: null,
    expected: 'string | number',
    received: 'null',
    message: 'Invalid type: Expected string | number but received null',
    issues: [
      {
        kind: 'schema',
        type: 'string',
        input: null,
        expected: 'string',
        received: 'null',
        message: 'Invalid type: Expected string but received null',
      },
      {
        kind: 'schema',
        type: 'number',
        input: null,
        expected: 'number',
        received: 'null',
        message: 'Invalid type: Expected number but received null',
      },
    ],
  },
];

variant 模式

为了更好的性能、更强的类型安全和更具针对性的问题输出,你可以为可辨识联合使用 variant。因此,只要有可能,我们都建议使用 variant 而非 union。可辨识联合是对象之间的“或”关系,可以通过一个特定的键来区分。

当你调用模式函数时,首先指定辨别器键(discriminator key)。这个键用于根据输入确定要使用的验证模式。对象模式(以数组形式)作为第二个参数紧随其后。

import * as v from 'valibot';

const VariantScheme = v.variant('type', [
  v.object({
    type: v.literal('foo'),
    foo: v.string(),
  }),
  v.object({
    type: v.literal('bar'),
    bar: v.number(),
  }),
]);

对于非常复杂的数据集,多个 variant 模式也可以相互深度嵌套。