# Unions

URL: https://caijiao.org/zod/unions
Source: docs/zod/unions.md
Description: 联合类型的使用和验证策略，包括多类型选择、可识别联合类型和类型收窄

Zod 提供了内置的 `z.union` 方法来创建联合类型。

## 基本用法

```ts
import { z } from "zod";

// 创建联合类型
const stringOrNumber = z.union([z.string(), z.number()]);

stringOrNumber.parse("hello"); // 通过
stringOrNumber.parse(42);      // 通过
stringOrNumber.parse(true);    // 失败
```

## 使用 .or() 方法

为了方便，你也可以使用 `.or()` 方法：

```ts
const stringOrNumber = z.string().or(z.number());
const stringOrNumberOrBoolean = z.string()
  .or(z.number())
  .or(z.boolean());
```

## 判别联合类型

判别联合类型是指联合类型中的每个成员都有一个共同的、具有不同值的属性：

```ts
const result = z.discriminatedUnion("status", [
  z.object({
    status: z.literal("success"),
    data: z.string(),
  }),
  z.object({
    status: z.literal("error"),
    error: z.instanceof(Error),
  }),
]);

// 验证成功的情况
result.parse({
  status: "success",
  data: "成功了！",
}); // 通过

// 验证错误的情况
result.parse({
  status: "error",
  error: new Error("出错了"),
}); // 通过
```

## 访问联合选项

你可以使用 `.options` 属性获取联合类型的所有选项：

```ts
const myUnion = z.discriminatedUnion("status", [
  z.object({ status: z.literal("loading") }),
  z.object({ status: z.literal("success") }),
  z.object({ status: z.literal("error") }),
]);

console.log(myUnion.options); // 获取所有选项
```

## 合并判别联合类型

要合并两个或更多判别联合类型，可以展开它们的 `.options`：

```ts
const A = z.discriminatedUnion("status", [
  z.object({ status: z.literal("loading") }),
  z.object({ status: z.literal("success") }),
]);

const B = z.discriminatedUnion("status", [
  z.object({ status: z.literal("error") }),
  z.object({ status: z.literal("timeout") }),
]);

const Combined = z.discriminatedUnion("status", [
  ...A.options,
  ...B.options,
]);
```

## 错误处理

对于判别联合类型，Zod 会根据判别字段的值来确定使用哪个模式进行验证，这样可以提供更精确的错误信息：

```ts
const result = z.discriminatedUnion("status", [
  z.object({
    status: z.literal("success"),
    data: z.string(),
  }),
  z.object({
    status: z.literal("error"),
    message: z.string(),
  }),
]);

// 当提供了错误的字段时
result.parse({
  status: "success",
  message: "这不应该在这里", // 错误：success 状态应该有 data 字段
}); // 将抛出特定的错误
```
