# 递归类型

URL: https://caijiao.org/zod/recursive-types
Source: docs/zod/recursive-types.md
Description: 递归类型的定义和使用方法，包括自引用类型和复杂嵌套数据结构的处理

Zod 支持递归模式，这对于验证嵌套数据结构非常有用。

## 基本递归

使用 `z.lazy()` 创建递归模式：

```ts
import { z } from "zod";

// 定义一个递归的类别结构
type Category = {
  name: string;
  subcategories: Category[];
};

const Category: z.ZodType<Category> = z.lazy(() =>
  z.object({
    name: z.string(),
    subcategories: z.array(Category),
  })
);

// 验证
Category.parse({
  name: "食品",
  subcategories: [
    {
      name: "水果",
      subcategories: [
        {
          name: "热带水果",
          subcategories: [],
        },
      ],
    },
  ],
}); // 通过
```

## 互递归类型

你可以定义多个相互递归的类型：

```ts
// 文件系统示例
const FileSystem = z.lazy(() =>
  z.object({
    type: z.literal("directory"),
    children: z.array(z.union([File, FileSystem])),
  })
);

const File = z.object({
  type: z.literal("file"),
  content: z.string(),
});

// 验证
FileSystem.parse({
  type: "directory",
  children: [
    {
      type: "file",
      content: "hello.txt",
    },
    {
      type: "directory",
      children: [
        {
          type: "file",
          content: "world.txt",
        },
      ],
    },
  ],
}); // 通过
```

## JSON 类型

使用递归类型定义 JSON 数据结构：

```ts
const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
type Literal = z.infer<typeof literalSchema>;

const JsonSchema: z.ZodType<Json> = z.lazy(() =>
  z.union([
    literalSchema,
    z.array(JsonSchema),
    z.record(JsonSchema),
  ])
);

type Json = Literal | { [key: string]: Json } | Json[];

// 验证
JsonSchema.parse({
  string: "hello",
  number: 42,
  array: [1, 2, 3],
  object: {
    nested: {
      data: [true, null, "world"],
    },
  },
}); // 通过
```

## 性能考虑

递归类型可能会影响验证性能，特别是对于深度嵌套的数据：

```ts
// 添加最大深度限制
const LimitedCategory = z.lazy(() =>
  z.object({
    name: z.string(),
    subcategories: z.array(LimitedCategory).max(5), // 限制子类别数量
  })
);

// 添加最大递归深度
let depth = 0;
const MaxDepthCategory = z.lazy(() => {
  if (depth > 3) throw new Error("最大递归深度超出");
  depth++;
  return z.object({
    name: z.string(),
    subcategories: z.array(MaxDepthCategory),
  });
});
```

## 类型推断

TypeScript 可以正确推断递归类型：

```ts
const Comment = z.lazy(() =>
  z.object({
    text: z.string(),
    replies: z.array(Comment),
  })
);

type Comment = z.infer<typeof Comment>;
// {
//   text: string;
//   replies: Comment[];
// }

// 使用类型
const comment: Comment = {
  text: "父评论",
  replies: [
    {
      text: "子评论",
      replies: [],
    },
  ],
};
```
