如何在 TypeScript 中遍历枚举以生成单选按钮:教程

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么枚举和单选按钮是完美搭配?

\n

想象一下:您正在用 TypeScript 编写一个表单。需要让用户从多个选项中选择一个——例如,难度级别、订单状态或性别。这些选项存储在哪里?您可以硬编码一个字符串数组,但这是一条死路。当选项增多时,您会感到困惑,如果业务逻辑发生变化,您将不得不在十个地方修改代码。

\n

这时,枚举(enum) 就登场了。它们允许您定义一组命名常量,既便于人类阅读,也能被机器理解。而单选按钮则是从列表中选择单个值的经典 UI 元素。将两者结合,意味着获得干净、可维护的代码。听起来很棒,但有一个问题:如何遍历枚举以在模板中显示它?这正是成千上万的开发者在 Stack Overflow 上纠结的问题。让我们一劳永逸地解决它。

\n\n

问题:枚举不是数组

\n

在 TypeScript 中,枚举不仅仅是一个字符串列表。根据您声明它的方式(数值型或字符串型),它的行为也不同。数值型枚举会创建反向映射:键 -> 值和值 -> 键。字符串型枚举则只有正向映射。因此,简单地写 for (let item in MyEnum) 是个坏主意。您不仅会得到所需的键,还会得到多余的反向映射。

\n

下面是一个典型的陷阱:

\n
enum Status {\n  Active = 1,\n  Inactive = 2,\n  Pending = 3\n}\n\n// 不要这样做\nfor (let key in Status) {\n  console.log(key); // "1", "2", "3", "Active", "Inactive", "Pending"\n}\n
\n

看到了吗?控制台输出了名称和值。如果您尝试将其显示为单选按钮,用户会看到难以理解的数字。这不符合我们的需求。

\n\n

解决方案 #1:对字符串枚举使用 Object.values()

\n

最简单且最可靠的方法是使用 Object.values()。此方法返回对象可枚举属性的值数组。对于字符串枚举,它完美工作,因为它们(几乎总是)没有反向映射。

\n\n

示例:订单状态

\n
enum OrderStatus {\n  New = 'new',\n  Processing = 'processing',\n  Shipped = 'shipped',\n  Delivered = 'delivered',\n  Cancelled = 'cancelled'\n}\n\n// 获取值数组\nconst statusValues = Object.values(OrderStatus);\n// ['new', 'processing', 'shipped', 'delivered', 'cancelled']\n\n// 现在可以轻松在模板中显示(React)\nfunction StatusSelector() {\n  return (\n    <div>\n      {statusValues.map((status) => (\n        <label key={status}>\n          <input type="radio" name="status" value={status} />\n          {status}\n        </label>\n      ))}\n    </div>\n  );\n}\n
\n

一切简单而巧妙。我们得到了一个字符串数组,然后直接遍历它。适用于 React、Angular、Vue 等任何框架。

\n\n

解决方案 #2:对数值枚举使用 Object.keys() + 过滤

\n

对于数值枚举,情况更复杂一些。Object.values() 不仅会返回字符串键,还会返回数值,因为 JavaScript 将它们视为对象的“属性”。我们需要只过滤出字符串(键)。

\n\n

示例:访问级别

\n
enum AccessLevel {\n  Guest = 0,\n  User = 1,\n  Moderator = 2,\n  Admin = 3\n}\n\n// 过滤:只保留字符串(键)\nconst levelKeys = Object.keys(AccessLevel).filter(key => isNaN(Number(key)));\n// ['Guest', 'User', 'Moderator', 'Admin']\n\n// 如果需要获取对象数组以便于显示\nconst levelOptions = levelKeys.map(key => ({\n  label: key,\n  value: AccessLevel[key as keyof typeof AccessLevel]\n}));\n// [\n//   { label: 'Guest', value: 0 },\n//   { label: 'User', value: 1 },\n//   ...\n// ]\n
\n

现在您有了一个选项数组,其中 label 是人类可读的名称,而 value 是便于

博客

书籍推荐