TypeScript带值枚举使用问题:传入枚举键时Mongoose验证失败
枚举键传入Mongoose模型的验证问题解决
问题描述
使用带值的TypeScript枚举时,想要传入枚举的键(如HA)作为campaign字段值,但触发Mongoose验证错误:
"error": "Appeal validation failed: campaign:
\"HA\"is not a valid enum value for pathcampaign."
尝试将模型中的enum配置改为Object.keys(Campaign)后仍无效,相关代码如下:
相关代码
appealTypes.ts
export enum Campaign { E = "Eid", R = "Ramadan", HA = "Hunger Appeal" } export interface Appeal { _id: string; title: string; campaign: Campaign; }
appealModel.ts
const appealSchema = new mongoose.Schema<Appeal>( { title: { type: String, required: true, }, campaign: { type: String, enum: Object.values(Campaign), // required: true, }, }, { timestamps: true } );
appealController.ts
const createAppeal = async (request: Request, response: Response) => { try { const { title, campaign} = request.body; const newAppeal = await appealModel.create({ title, campaign }); response.status(201).json({ message: "Appeal created successfully", data: newAppeal, }); } catch (error) { console.error("Error creating appeal:", error); response.status(500).json({ message: "Error creating appeal", error: error instanceof Error ? error.message : "Unknown error", }); } };
问题原因与解决方法
问题核心是TypeScript字符串枚举的双向映射特性,和Mongoose的验证规则不匹配:
- 当前模型用
Object.values(Campaign)作为枚举值,对应["Eid", "Ramadan", "Hunger Appeal"],但你传入的是枚举键HA,自然不匹配。 - 直接用
Object.keys(Campaign)会返回["E", "R", "HA", "Eid", "Ramadan", "Hunger Appeal"]——因为TypeScript会为字符串枚举生成双向映射,导致验证逻辑混乱。
正确解决步骤
1. 确定存储规则:存枚举键还是值
如果要存枚举键(E/R/HA):
- 过滤出枚举的纯键,排除反向映射的值:
// 过滤仅保留枚举的键 const campaignKeys = Object.keys(Campaign).filter(key => isNaN(Number(key))); const appealSchema = new mongoose.Schema<Appeal>( { title: { type: String, required: true }, campaign: { type: String, enum: campaignKeys, // 此时枚举值为["E", "R", "HA"] // required: true, }, }, { timestamps: true } );
2. 匹配TypeScript类型
如果存键,需要调整接口类型或在控制器转换:
- 调整接口类型:
export interface Appeal { _id: string; title: string; campaign: keyof typeof Campaign; // 类型限定为"E"|"R"|"HA" }
- 或者在控制器将传入的字符串转为枚举成员:
const newAppeal = await appealModel.create({ title, campaign: Campaign[campaign as keyof typeof Campaign] });
3. 支持键/值双输入(可选)
如果需要同时兼容传入键或值,可在控制器做前置转换:
let campaignValue: string; if (Object.keys(Campaign).includes(campaign)) { // 传入的是键,转成对应值 campaignValue = Campaign[campaign as keyof typeof Campaign]; } else if (Object.values(Campaign).includes(campaign)) { // 传入的是值,直接使用 campaignValue = campaign; } else { throw new Error("无效的campaign值"); } const newAppeal = await appealModel.create({ title, campaign: campaignValue });
内容的提问来源于stack exchange,提问作者Fuaad
相关产品推荐
相关产品推荐

