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

如何在TypeScript中获取对象里标志枚举的激活标志?

TypeScript中实现类似C#标志枚举的优雅方案

问题场景

我希望在TypeScript中实现类似C#标志枚举(flag enums)的功能:打印对象时输出激活的标志名称,而非累加的整数值。现有如下枚举及对象:

enum Weekdays {
  None = 0,
  Monday = 1 << 0,
  Tuesday = 1 << 1,
  Wednesday = 1 << 2, 
  Thursday = 1 << 3,
  Friday = 1 << 4,
  Saturday = 1 << 5,
  Sunday = 1 << 6
}

let obj = {
  workdays: Weekdays.Monday | Weekdays.Tuesday | Weekdays.Wednesday | Weekdays.Thursday | Weekdays.Friday
};

直接用console.log打印会得到:

{
  "workdays": 31
}

目前我只能通过遍历枚举结合位运算检查标志:

if ((obj.workdays & Weekdays.Monday) === Weekdays.Monday) {
  // 标志已激活
}

但这种方法在枚举规模扩大时效率偏低,我想找到更优雅的实现方式,曾尝试编写泛型函数但未成功。


解决方案

1. 优雅打印激活的标志名称

封装通用函数将标志枚举值转换为名称列表,自动处理None的情况:

function getFlagNames<T extends number>(enumObj: Record<string, T>, value: T): string[] {
  if (value === 0) {
    return [enumObj[0] as unknown as string];
  }
  return Object.entries(enumObj)
    .filter(([key, enumValue]) => !isNaN(Number(key)) && (value & enumValue) === enumValue)
    .map(([key]) => key);
}

// 使用示例
console.log(getFlagNames(Weekdays, obj.workdays)); 
// 输出: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

// 拼接为字符串
console.log(getFlagNames(Weekdays, obj.workdays).join(", "));
// 输出: "Monday, Tuesday, Wednesday, Thursday, Friday"

如果需要格式化整个对象,可以再封装一层:

function formatFlagObject<T extends Record<string, number>>(obj: T, enumMap: Record<string, number>): Record<string, string> {
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [
      key,
      getFlagNames(enumMap, value).join(", ")
    ])
  );
}

// 使用示例
console.log(formatFlagObject(obj, Weekdays));
// 输出: { workdays: "Monday, Tuesday, Wednesday, Thursday, Friday" }

2. 优雅检查标志激活状态

将重复的位运算逻辑封装为通用函数,避免冗余代码:

// 检查单个标志是否激活
function hasFlag<T extends number>(value: T, flag: T): boolean {
  return (value & flag) === flag;
}

// 使用示例
if (hasFlag(obj.workdays, Weekdays.Monday)) {
  console.log("包含周一");
}

// 检查多个标志是否同时激活
function hasAllFlags<T extends number>(value: T, flags: T): boolean {
  return (value & flags) === flags;
}

if (hasAllFlags(obj.workdays, Weekdays.Monday | Weekdays.Friday)) {
  console.log("同时包含周一和周五");
}

// 检查是否包含任意一个目标标志
function hasAnyFlag<T extends number>(value: T, flags: T): boolean {
  return (value & flags) !== 0;
}

if (hasAnyFlag(obj.workdays, Weekdays.Saturday | Weekdays.Sunday)) {
  console.log("包含周末");
}

3. 类型增强(可选)

通过TypeScript类型约束确保传入的是合法枚举值,提升代码安全性:

type FlagEnum<T> = T extends number ? T : never;

function hasFlagStrict<T extends FlagEnum<T>>(value: T, flag: T): boolean {
  return (value & flag) === flag;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 07:55:41