在 TypeScript 中转换 FlaggedEnum
Convert FlaggedEnum in TypeScript
我有一个这样的枚举,
enum Traits {
None = 0,
Friendly = 1 << 0, // 0001
Mean = 1 << 1, // 0010
Funny = 1 << 2, // 0100
Boring = 1 << 3, // 1000
All = ~(~0 << 4) // 1111
}
let traits = Traits.Mean | Traits.Funny
console.log(traits);
此控制台将记录 6
。反过来怎么办?
如果我通过 6 。我想得到 Traits.Mean , Traits.Funny
.
你可以这样做:
for (var prop in Traits) {
if(Traits[prop] & 6) {
console.log(prop);
}
}
虽然 enum
的定义值的名称在运行时出现在表示 enum
类型的对象中,但复合值不存在。我们可以编写一个函数来计算复合显示字符串:
enum Traits {
None = 0,
Friendly = 1 << 0, // 0001
Mean = 1 << 1, // 0010
Funny = 1 << 2, // 0100
Boring = 1 << 3, // 1000
FunnyBoringCustom = Funny | Boring, // Defined compund
All = ~(~0 << 4) // 1111
}
let traits = Traits.Mean | Traits.Funny
function enumToString<T extends { [name: string]: any }>(enumType: T, enumValue: T[keyof T], separator = ','){
// Predefined value
if(enumType[enumValue]!== undefined){
return enumType[enumValue];
}
let values = Object
.getOwnPropertyNames(enumType)
// We only take numeric values, the enum contains both direct and reverse lookup
.filter(x => Number.isInteger(enumType[x]) && enumType[x] != 0)
// Sort the values, so that compound values will be before their constituents
.sort((a,b) => enumType[b] - enumType[a]);
var result = "";
for(let e of values){
if((enumValue & enumType[e]) == enumType[e] ){
result += result !== "" ? separator: "";
result+=e;
// Exclude the bits that were in this value, to treat defined compound values correcty.
enumValue = enumValue & (~enumType[e]);
}
}
return result;
}
// Usage
console.log(enumToString(Traits, traits)); // Funny,Mean
console.log(enumToString(Traits, 6)); // Funny,Mean
console.log(enumToString(Traits, Traits.Friendly | Traits.Boring)) //Boring,Friendly
console.log(enumToString(Traits, Traits.Funny | Traits.Boring)) //FunnyBoringCustom
console.log(enumToString(Traits, Traits.All)); // All
编辑
正如我们所看到的,该函数做了相当多的工作,我们可以缓存结果。
我们可以在 enum
对象本身中这样做:
function enumToString<T extends { [name: string]: any }>(enumType: T, enumValue: T[keyof T], separator = ','){
...
enumType[enumValue] = result;
return result;
}
或者我们可以创建一个包装版本的函数,为每种类型缓存在不同的对象中:
function cachedEnumToString<T extends { [name: string]: any }>(enumType: T, separator = ',') {
let cache: { [name: string]: string } = {};
return function forValue(enumValue: T[keyof T]) {
var result = cache[enumValue];
if (!result) {
result = enumToString(enumType, enumValue, separator);
cache[enumValue] = result;
}
return result
}
}
// Usage
const traitsToString = cachedEnumToString(Traits);
console.log(traitsToString(traits));
console.log(traitsToString(6));
console.log(traitsToString(Traits.Friendly | Traits.Boring))
console.log(traitsToString(Traits.Funny | Traits.Boring))
console.log(traitsToString(Traits.All));
我有一个这样的枚举,
enum Traits {
None = 0,
Friendly = 1 << 0, // 0001
Mean = 1 << 1, // 0010
Funny = 1 << 2, // 0100
Boring = 1 << 3, // 1000
All = ~(~0 << 4) // 1111
}
let traits = Traits.Mean | Traits.Funny
console.log(traits);
此控制台将记录 6
。反过来怎么办?
如果我通过 6 。我想得到 Traits.Mean , Traits.Funny
.
你可以这样做:
for (var prop in Traits) {
if(Traits[prop] & 6) {
console.log(prop);
}
}
虽然 enum
的定义值的名称在运行时出现在表示 enum
类型的对象中,但复合值不存在。我们可以编写一个函数来计算复合显示字符串:
enum Traits {
None = 0,
Friendly = 1 << 0, // 0001
Mean = 1 << 1, // 0010
Funny = 1 << 2, // 0100
Boring = 1 << 3, // 1000
FunnyBoringCustom = Funny | Boring, // Defined compund
All = ~(~0 << 4) // 1111
}
let traits = Traits.Mean | Traits.Funny
function enumToString<T extends { [name: string]: any }>(enumType: T, enumValue: T[keyof T], separator = ','){
// Predefined value
if(enumType[enumValue]!== undefined){
return enumType[enumValue];
}
let values = Object
.getOwnPropertyNames(enumType)
// We only take numeric values, the enum contains both direct and reverse lookup
.filter(x => Number.isInteger(enumType[x]) && enumType[x] != 0)
// Sort the values, so that compound values will be before their constituents
.sort((a,b) => enumType[b] - enumType[a]);
var result = "";
for(let e of values){
if((enumValue & enumType[e]) == enumType[e] ){
result += result !== "" ? separator: "";
result+=e;
// Exclude the bits that were in this value, to treat defined compound values correcty.
enumValue = enumValue & (~enumType[e]);
}
}
return result;
}
// Usage
console.log(enumToString(Traits, traits)); // Funny,Mean
console.log(enumToString(Traits, 6)); // Funny,Mean
console.log(enumToString(Traits, Traits.Friendly | Traits.Boring)) //Boring,Friendly
console.log(enumToString(Traits, Traits.Funny | Traits.Boring)) //FunnyBoringCustom
console.log(enumToString(Traits, Traits.All)); // All
编辑
正如我们所看到的,该函数做了相当多的工作,我们可以缓存结果。
我们可以在 enum
对象本身中这样做:
function enumToString<T extends { [name: string]: any }>(enumType: T, enumValue: T[keyof T], separator = ','){
...
enumType[enumValue] = result;
return result;
}
或者我们可以创建一个包装版本的函数,为每种类型缓存在不同的对象中:
function cachedEnumToString<T extends { [name: string]: any }>(enumType: T, separator = ',') {
let cache: { [name: string]: string } = {};
return function forValue(enumValue: T[keyof T]) {
var result = cache[enumValue];
if (!result) {
result = enumToString(enumType, enumValue, separator);
cache[enumValue] = result;
}
return result
}
}
// Usage
const traitsToString = cachedEnumToString(Traits);
console.log(traitsToString(traits));
console.log(traitsToString(6));
console.log(traitsToString(Traits.Friendly | Traits.Boring))
console.log(traitsToString(Traits.Funny | Traits.Boring))
console.log(traitsToString(Traits.All));