为什么需要检查 TypeScript 枚举值?一个实际案例
\n\n想象一下:您正在使用 TypeScript 编写一个 Node.js 后端。客户端发送一个订单状态——字符串 "shipped"。您有一个包含以下选项的枚举 OrderStatus:Pending、Processing、Shipped、Delivered。但突然收到了 "CANCELLED" 或 "unknown"。该怎么办?正确做法是——检查 TypeScript 枚举中是否存在该值。
这个问题是 Stack Overflow 上最常见的问题之一(数千次浏览)。这并不奇怪:TypeScript 中的枚举不仅仅是一组常量,而是一个包含数字和字符串变体的复杂结构。在本指南中,我们将介绍所有检查枚举值存在性的方法,从简单到高级,并附有代码示例和解释。
\n\n无论您是刚开始学习 TypeScript,还是想加深理解,本文都适合您。让我们开始吧!
\n\n什么是 TypeScript 枚举?快速入门
\n\n枚举(Enum)是一种定义一组命名常量的方式。TypeScript 中有两种类型的枚举:
\n\n- \n
- 数字枚举——值会自动递增(0, 1, 2...)。 \n
- 字符串枚举——每个成员都显式分配一个字符串。 \n
数字枚举示例:
\n\nenum Direction {\n Up, // 0\n Down, // 1\n Left, // 2\n Right // 3\n}\n\n字符串枚举示例:
\n\nenum Status {\n Active = "ACTIVE",\n Inactive = "INACTIVE",\n Pending = "PENDING"\n}\n\n为什么要检查值?因为来自外部(API、表单、数据库)的数据可能是任意的。不进行检查,您可能会得到 undefined 或运行时错误。
方法 1. 经典方法:Object.values() + includes()
\n\n最流行且可读性最高的方法是将枚举转换为值数组,然后使用 includes() 检查是否存在。
对于字符串枚举:
\n\nenum Color {\n Red = "RED",\n Green = "GREEN",\n Blue = "BLUE"\n}\n\nfunction isColor(value: string): boolean {\n return Object.values(Color).includes(value as Color);\n}\n\nconsole.log(isColor("RED")); // true\nconsole.log(isColor("YELLOW")); // false\n\n对于数字枚举——有个小技巧!Object.values() 会返回反向映射(键和值)。因此需要只过滤数字:
enum NumberEnum {\n A = 1,\n B = 2,\n C = 3\n}\n\nfunction isNumberEnumValue(value: number): boolean {\n return Object.values(NumberEnum).filter(v => typeof v === 'number').includes(value);\n}\n\nconsole.log(isNumberEnumValue(2)); // true\nconsole.log(isNumberEnumValue(5)); // false\n\n这种方法通用性强,但处理数字枚举时需要小心。优点:简单直观。缺点:需要记住进行过滤。
\n\n方法 2. 类型守卫:通过枚举键进行检查
\n\n如果您不仅需要检查值,还需要获得类型保证,请使用类型守卫。这种方法在处理 API 时特别有用,因为它可以帮助您缩小类型范围。
\n\nenum UserRole {\n Admin = "admin",\n User = "user",\n Guest = "guest"\n}\n\nfunction isUserRole(value: string): value is UserRole {\n return Object.values(UserRole).includes(value as UserRole);\n}\n\nfunction processRole(role: string) {\n if (isUserRole(role)) {\n // TypeScript 知道 role 是 UserRole 类型\n console.log(`角色: ${role}`);\n } else {\n console.log("未知角色");\n }\n}\n\nprocessRole("admin"); // 角色: admin\nprocessRole("moderator"); // 未知角色\n\n这种方法提供了类型安全性,并减少了代码中的检查次数。我建议在严肃项目中使用。
\n\n