You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Zod枚举动态生成shadcn表单的SelectItem?

从Zod枚举动态生成shadcn Select选项的可行方案

当然可行,这是避免重复维护枚举选项的最佳实践之一,核心思路是从Zod定义的枚举类型中提取枚举值,转换为shadcn Select组件所需的SelectItem结构(通常是包含value和label的对象)。

具体实现步骤与代码示例

1. 定义包含枚举字段的Zod Schema

首先确保你的Zod Schema中明确使用枚举类型(可以是Zod原生的z.enum或绑定TS原生枚举的z.nativeEnum):

import { z } from "zod";

// 方式1:使用Zod原生枚举
const Field3ZodEnum = z.enum(["USER_ADMIN", "USER_EDITOR", "USER_VIEWER", "USER_GUEST"]);

// 方式2:使用TS原生枚举(可选)
enum Field3NativeEnum {
  Admin = "USER_ADMIN",
  Editor = "USER_EDITOR",
  Viewer = "USER_VIEWER",
  Guest = "USER_GUEST",
}

// 最终的表单验证Schema
const FormSchema = z.object({
  field1: z.string(),
  field2: z.string(),
  // 二选一:使用Zod枚举或TS原生枚举
  field3: Field3ZodEnum,
  // field3: z.nativeEnum(Field3NativeEnum),
});

2. 编写工具函数生成SelectItem数组

编写通用函数从Zod枚举中提取选项,转换为符合shadcn要求的格式:

// 针对Zod原生枚举的工具函数
const getSelectItemsFromZodEnum = <T extends z.ZodEnum<any>>(zodEnum: T) => {
  return zodEnum.options.map(option => ({
    value: option,
    // 可选:格式化显示文本,比如把下划线替换为空格并转大写
    label: option.replace(/_/g, " ").toUpperCase()
  }));
};

// 针对TS原生枚举的工具函数(如果用了nativeEnum)
const getSelectItemsFromNativeEnum = <T extends object>(nativeEnum: T) => {
  return Object.entries(nativeEnum).map(([labelKey, value]) => ({
    value,
    // 可选:把枚举键名(驼峰)格式化为友好文本
    label: labelKey.replace(/([A-Z])/g, " $1").trim()
  }));
};

// 生成field3的Select选项数组
const field3Options = getSelectItemsFromZodEnum(Field3ZodEnum);
// 如果用TS原生枚举则用这个:
// const field3Options = getSelectItemsFromNativeEnum(Field3NativeEnum);

3. 在shadcn Select组件中使用动态选项

直接将生成的选项数组渲染到Select组件中:

import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
// 假设已经用react-hook-form结合Zod处理表单逻辑
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

export function MyForm() {
  const form = useForm({
    resolver: zodResolver(FormSchema),
    defaultValues: {
      field1: "",
      field2: "",
      field3: ""
    }
  });

  return (
    <form onSubmit={form.handleSubmit((data) => console.log(data))}>
      {/* 其他表单字段... */}
      <Select {...form.register("field3")}>
        <SelectTrigger>
          <SelectValue placeholder="选择用户角色" />
        </SelectTrigger>
        <SelectContent>
          {field3Options.map(option => (
            <SelectItem key={option.value} value={option.value}>
              {option.label}
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
      <button type="submit">提交</button>
    </form>
  );
}

优势说明

  • 只需要维护一处枚举定义(Zod或TS枚举),修改枚举值后Select选项会自动同步,彻底避免重复维护的问题
  • 工具函数可以复用在其他需要从枚举生成Select选项的场景中
  • 格式化逻辑可以根据需求灵活调整,比如自定义显示文本的样式

内容的提问来源于stack exchange,提问作者Cheekumz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:07:43