Hur får man alla Enum-flaggor från ett nummer i TypeScript?
Givet:
Enum: {1, 4, 16}
Flaggor: 20
När: Jag skickar flaggor till en funktion
Då: Jag får en array av flaggor för det givna Enum: [4, 16]
Obs: Jag har försökt att konvertera Enum till en array manuellt och behandla värdena som siffror. Men jag blir överväldigad när det gäller TS och jag vill göra den funktionen dynamisk ifall Enum ändras. Jag vill verkligen inte hårdkoda det. Snälla hjälp!
enum Enum {
one = 1,
four = 4,
sixteen = 16,
}
const Flags: number = 20;
function getEnumValues(flags: number): Enum[] {
const enumFlags = [1, 4, 16];
const enums: Enum[] = [];
enumFlags.forEach(ef => {
if ((ef & flags) != 0) {
enums.push(ef);
}
})
return enums;
}
console.log(getEnumValues(Flags));
Lösning hittad här: Typescript flaggad enum få värden är inte bra eftersom min Enum inte är en sekvens, 2 och 8 saknas.
Svar #1
Jag har stött på en liknande utmaning tidigare. Och av en slump har jag skrivit en artikel om det, eftersom det var en riktigt intressant utmaning.
Det första du behöver är en hjälpare som extraherar Enum:s flaggor som en array genom att behandla TS enum som ett vanligt objekt. Därefter är ditt tillvägagångssätt redo att användas genom att loopa över flaggorna och se om de finns i ditt nummer.
Utdrag kopierat från koden sandbox ovanför länken.
const isPowerOfTwo = (x: number): boolean => {
return x != 0 && (x & (x - 1)) == 0;
};
export function getEnumFlags<
O extends object,
K extends O[keyof O] = O[keyof O]
>(obj: O): K[] {
const isFlag = (arg: string | number | K): arg is K => {
const nArg = Number(arg);
const isNumber = !Number.isNaN(nArg);
return isNumber && isPowerOfTwo(nArg);
};
const enumFlags: K[] = [];
Object.keys(obj).forEach(key => {
const nKey = Number(key);
if (isFlag(nKey)) {
enumFlags.push(nKey);
}
});
return enumFlags;
}
Redigera 2024.06.12: Mitt svar hanterar kantfall när enum har mellanliggande värden som används för bekvämlighet. T.ex.: enum MyEnum { first=1, second=2, both=3 } - both är INTE en flagga, det är en bekvämlighet istället för att skriva first | second.
Svar #2
Om din oro är att du upprepar Enum-värdena i enumFlags-arrayen i funktionen, kan du hämta dem dynamiskt:
const enumFlags = Object.values(Enum)
.filter((value): value is number => typeof value === "number");
Du behöver göra filter-callbacken till en typvaktfunktion (använda en typ-predikat, value is number) eftersom TypeScript annars tror att arrayen är av typen (string | Enum)[]. Men vi vet att den inte är det, eftersom vi gör typeof === "number".
Lekplatslänk
Eftersom det inte är gratis att bygga den arrayen kan det vara värt att göra det en gång, precis efter Enum-definitionen, och återanvända den. Det sagt, även om det inte är gratis, är det verkligen billigt (och att behålla den är inte gratis heller: den upptar [lite] minne).
