What is the best way to extract all Enum Flags based on a Number in TypeScript?

Given:
Enum: {1, 4, 16}
Flags: 20

When: I provide the Flags value to a function

Then: The output will be an array of flags corresponding to the given Enum: [4, 16]

Note: I attempted to manually convert the Enum to an array and treat values as numbers. However, I encountered difficulties when transitioning to TS and I aim to create a function that is adaptable in case the Enum is modified. I prefer not to hardcode it. Any assistance would be greatly appreciated!

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));

Solution referred from: Typescript flagged enum get values. However, this solution does not align with my Enum as it lacks sequences 2 and 8.

Answer №1

If you're worried about constantly listing the Enum values in the enumFlags array within the function, there's a way to generate them dynamically:

const enumFlags = Object.values(Enum)
    .filter((value): value is number => typeof value === "number");

It's important to use the type guard function in the filter callback (such as using a type predicate, like value is number), otherwise TypeScript might incorrectly infer the array type as (string | Enum)[]. By specifying typeof === "number", we ensure that this isn't the case.

Playground link

Sometimes it's beneficial to generate the array just once, right after defining Enum, and then reuse it rather than recreating it each time. While it does come with some cost, it's negligible (and keeping the array also incurs [minimal] memory usage).

Answer №2

I faced a similar challenge previously and coincidentally, I happened to write an article about it because it was quite an intriguing problem.

If you're interested, you can check out the article here: https://dev.to/sincovschi/bitwise-enum-flags-to-generate-html-from-array-3576

To tackle this challenge, you'll first need a helper function that extracts Enum's flags as an array by treating TS enum as a regular object. Once you have this helper in place, you can proceed with your approach by looping through the flags and checking if they exist in your number.

The code snippet below is taken from the code sandbox linked above:

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;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring Typescript: A guide to iterating through a Nodelist of HTML elements and retrieving their values

I'm struggling to retrieve values from a Nodelist of input elements. Can anyone help me out? let subtitleElements = document.querySelectorAll( '.add-article__form-subtitle' ); ...

Could you please clarify the type of event on the onInputChange props?

I am encountering an issue with using React.ChangeEvent on the mui v4 autocomplete component as I prefer not to use any other method. However, I keep getting an error indicating that the current event is incompatible. const handle = (e: React.ChangeEv ...

Ensure that the MUI icon color is set accurately

I created a functional component to set default values for react-admin's BooleanField. Here is the code: import ClearIcon from '@mui/icons-material/Clear' import DoneIcon from '@mui/icons-material/Done' import get from ...

Inform the Angular2 Component regarding the creation of DOM elements that are placed outside of the

The Challenge In my Angular2 project, I am using Swiper carousel and building it with Webpack. However, Angular2 adds random attributes like _ngcontent-pmm-6 to all elements in a component. Swiper generates pagination elements dynamically, outside of Ang ...

The upload cannot be completed as the file upload is not in a multipart request format

This file upload code was referenced from this source. The issue lies in the fact that it is sending the request as JSON instead of multipart form data, causing the server side code to reject the request and resulting in a failed upload. I have confirmed ...

Is Angular CLI incorrectly flagging circular dependencies for nested Material Dialogs?

My Angular 8 project incorporates a service class that manages the creation of dialog components using Angular Material. These dialogs are based on different component types, and the service class is designed to handle their rendering. Below is a simplifie ...

What is causing the issue with TypeScript's React.createRef() and its compatibility with the material-ui Button element?

Running on React version 16.13.1, my component class includes a Material-UI Button component and a RefObject to access the button element. class Search extends React.Component<any, any>{ constructor(props: any) { super(props) this.streetV ...

Assuming control value accessor - redirecting attention

import { Component, Input, forwardRef, OnChanges } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'formatted-currency-input', templateUrl: '../v ...

Why aren't the child route components in Angular 6 loading properly?

I have encountered a small problem. I developed an app using Angular 6 with children routes implemented like this: { path:'pages', component:DatePagesComponent, children : [ {path:'404', component:Error404C ...

Mapping the response from an http.get call to create a new typed object instance in Angular 2

Can anyone help me understand how to map the result from a service call to an object using http.get and Observables in Angular 2? Please check out this example In my getPersonWithGetProperty method, I am trying to return an Observable of type PersonWithG ...

While using Angular CLI on GitLab CI, an error occurred indicating that the custom rule directory "codelyzer" could not be

ng lint is throwing an error on Gitlab CI stating: An unhandled exception occurred: Failed to load /builds/trade-up/trade-up/common/projects/trade-up-common/tslint.json: Could not find custom rule directory: codelyzer. The strange thing is that ng lint ru ...

How to correct placeholder text display in the input of a Material UI text field

Currently, I am utilizing the material ui text field component. The issue at hand is that when the text field is in focus, the placeholder shifts to the top of the field. https://i.stack.imgur.com/P5flf.png I prefer for the placeholder to remain within ...

When using TypeScript, the tls.TLSSocket() function may trigger an error mentioning the absence of a "socket" parameter

Currently, I am in the process of building a basic IRC bot and using raw sockets to connect to the IRC server. Initially written in plain Javascript, I am now transitioning it to TypeScript. However, I have encountered an unusual issue when attempting to c ...

Why is the selected option not visible in the Angular 8 drop-down?

This is a commonly asked question, but my situation seems to be unique. None of the existing answers have provided a solution for my specific issue. Here is the code that I am working with: <form (ngSubmit)="getExceptions(f)" #f="ngForm"> ...

How to access the result without using subscribe in Angular?

I am facing unexpected behavior with a method in my component: private fetchExternalStyleSheet(outerHTML: string): string[] { let externalStyleSheetText: string; let match: RegExpExecArray; const matchedHrefs = []; while (match = this.hrefReg.exe ...

Changing Observable to Promise in Angular 2

Q) What is the best way to convert an observable into a promise for easy handling with .then(...)? The code snippet below showcases my current method that I am looking to transform into a promise: this._APIService.getAssetTypes().subscribe( assetty ...

Creating a dynamic visual experience with Angular 2: How to implement multiple font colors

I have a text area which is connected to one string, with the default text color set to white. <textarea style="background-color: black;color:#fff;" [(ngModel)]="outputText"></textarea> The connected string contains multiple variables. retur ...

The ngOnInit function is not triggered upon instantiation of an Injectable class

What could be causing the ngOnInit() method not to be called upon resolution of an Injectable class? Code import {Injectable, OnInit} from 'angular2/core'; import { RestApiService, RestRequest } from './rest-api.service'; @Injectable ...

Can a TypeScript generator function be accurately typed with additional functionality?

Generator functions come with prototype properties that allow for the addition of behavior. The generated generators inherit this behavior. Unfortunately, TypeScript does not seem to recognize this feature, leaving me unsure of how to make it aware. For i ...

Verification for collaborative element

I am currently working on creating a shared component for file uploads that can be reused whenever necessary. Interestingly, when I include the file upload code in the same HTML as the form, the validation functions properly. However, if I extract it into ...