如何在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
相关产品推荐
相关产品推荐

