Retrieve the enum instance based on the specified type within a generic function

In this simplified example, we have a concept of tags, each defined by a single character. The "Flags" object accumulates these values based on an enum. The goal is to make the source code explicit, concise, easily refactorable, compiler-verified, and ensure that the object storing the flags is compact for efficient database storage.

class Flags<ENU>{
    s: string = "";
    set(v: ENU){
        this.s += v;
        return this;
    }
    has(v: ENU){
        return this.s.includes(v);
    }
}

enum TypeAnimal{
    Winged = "w",
    Legged = "l"
}

let flagsBird = new Flags<TypeAnimal>().set(TypeAnimal.Winged);

The objective is to check for any duplicated values in the enums used in this process. One approach could be passing the type as a parameter in the constructor instead of explicitly as a generic, allowing TypeScript to infer the generic type:

class Flags2<ENU>{
    s: string = "";
    constructor(enu: ENU){
        // Check the values in enu here.
    }
    set(v: ENU){
        this.s += v;    
        return this;
    }
    has(v: ENU){
        return this.s.includes(v);
    }
}

let flagsBird2 = new Flags2(TypeAnimal);

However, this approach leads to an error message:

flagsBird2.set(TypeAnimal.Winged);    // Argument of type 'TypeAnimal' is not assignable to parameter of type 'typeof TypeAnimal'.ts(2345)

I've experimented with different combinations of typeof but haven't found a working solution yet. Any suggestions or insights? It seems like there's more for me to explore regarding TypeScript and generics.

Answer №1

What advantages does using this compact encoding provide?

In my opinion, enums in TypeScript may not be as beneficial.

The preferred approach to tackle this issue is by utilizing types (remember, types can also be strings), instead of enums. The Set class automatically removes duplicates for you.

class Flags3<T extends string>{
    s: Set<string> = new Set();
    constructor(enu: readonly T[]) {
        // validate the values in enu here.
    }
    set(v: T) {
        this.s.add(v)
        return this;
    }
    has(v: T) {
        return this.s.has(v);
    }
}

// argument type below is ("legged" | "winged")[], NOT string[]
const f3 = new Flags3(["legged", "winged"]);

// or
// const animalTypes=["legged","winged"] as const;
// const f3 = new Flags3(animalTypes)

f3.set("legged"); // OK
f3.set("foo"); // compile time error

By specifying readonly T[] in the constructor parameter, we can deduce the individual types within the tuple passed to it.

Playground Link

Further reading about the drawbacks of enums in TypeScript

Answer №2

enum TypeAnimal{
    Winged = "w",
    Legged = "l"
}

// Customized class based on the initial scenario
class Flags2<ENU>{
    s: string = "";
    set(v: ENU){
        this.s += v;    // #fix prevent duplicates in this.s
        return this;
    }
    has(v: ENU){
        return this.s.includes(`${v}`);
    }
}

// Upgraded version utilizing a Set instead of a string to handle unique values.
class Flags3<ENU>{
    s: Set<ENU> = new Set();
    set(v: ENU){
        this.s.add(v);
        return this;
    }
    has(v: ENU){
        return this.s.has(v);
    }
}

let flagsBird2 = new Flags2<TypeAnimal>();
let flagsBird3 = new Flags3<TypeAnimal>();

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

The art of expanding Angular's HTTP client functionality

I understand that the following code is not valid in Angular, but I am using it for visual demonstration purposes. My goal is to enhance the Angular HTTP client by adding custom headers. I envision creating a class like this, where I extend the Angular h ...

What are the steps to customize the date pipe in Angular?

Encountered the InvalidPipeArgument issue with Safari for date/time format, but managed to resolve it by following the solution provided in this Stack Overflow thread. Currently using: <mat-cell *cdkCellDef="let payroll" fxFlex="20%"> {{payroll.tim ...

Subtracted TypeScript concept

Is it possible to create a modified type in Typescript for React components? import {Component, ComponentType} from 'react'; export function connect<S, A>(state: () => S, actions: A){ return function createConnected<P>(componen ...

Ways to reset an input field when focused

Looking to implement a number input field in React that clears the initial value when the user clicks on it. While there are solutions available for text inputs, I have not come across a method for number inputs. Every attempt I make at solving this issu ...

Having trouble with the npm Fluid Player installation

I am attempting to integrate Fluid Player into my Angular application Using - npm i fluid-player However, I'm encountering this error ...

Typescript: Using axios to retrieve POST response beyond function boundaries

I've been working on a Typescript function that is supposed to generate and return a token value. Everything seems to be functioning properly, but I'm encountering an issue where the token value is only being logged to the console instead of bein ...

"Utilizing Primeng's dynamic functionality to create a selected p-tab

Utilizing the TabView module from primeng, I have created a dynamic tab where only the last tab remains static. The property used is 'selected', and for the dynamic tab, it is set as [selected]="'tab' + $index", where $index represents ...

What could be causing the index.tsx file to not locate the Clock Module?

Here is the code snippet I have in my index.tsx file. import Clock from "./utility/clock"; And this is my tsconfig setup. { "compilerOptions": { "sourceMap": true, "noImplicitAny": true, "module": "es6", "target": "es5", ...

Tips on how to specify a reference to a pre-existing namespace that can be accessed from the JavaScript bundle while it is

I am in the process of developing a plugin for an existing JavaScript application called Forge Autodesk.Viewing. Recently, they have integrated THREE.js into their app bundle starting from version 6. Currently, I am able to utilize it within my plugin by ...

Confirm the identity of a user by checking their email against the records stored in a MySQL database

I am currently working on creating a user verification system using email that is stored in a mySql database and utilizing express JS. The user is required to input their email before filling out any other forms. If the email is not found in the email tabl ...

Verify the type without making any assumptions about the checked type

Take a look at this type definition: interface ISmth<T> { id: number; data: T; } Now, I am interested in creating an array that contains elements of this type: var a = [{ id: 1, data: [], }, { id: 2, data: 4, }, { id: 3, data: "abc ...

Ways to verify if a certain type possesses an index signature during runtime

Is it possible to create a type guard in JavaScript that checks if a given type implements an index signature? I'm unsure if this concept would be viable, but here is the idea: I am looking for guidance on how to implement the logic within this funct ...

What are the best practices for implementing MapLabel in an Angular project?

I need help displaying text on top of multiple polygons on a map. I've heard that Map Label can help with this, but I'm having trouble implementing it and can't find any NPM resources. Here is the Stack Blitz URL for reference: https://stac ...

Develop a dynamic component using ComponentFactoryResolver that implements a dynamic template

I am looking to create a unique dynamic component with a custom template that resolves interpolations based on the dynamic component's context. To achieve this, I understand that I can utilize the following code snippet to generate a dynamic componen ...

Winston logs are unable to function within the Docker Container

I'm currently working on developing a nodejs/express app with typescript and have recently installed the winston package using npm install winston. I came across this helpful article that I've been following closely. Now, my goal is to dockerize ...

Unable to destructure props and assign them to a react-bootstrap component

I recently installed react-bootstrap and I am looking to customize the default buttons in my project. My goal is to simplify the button creation process by just using <Button> without specifying a variant option for most buttons. import * as bs from ...

Utilizing an external type definition in JSDoc @typedef

I'm encountering an issue with reducing redundancy when defining my imported types. I am trying to streamline the process, but unfortunately I am running into errors. /** @typedef {import("../types/util")} util @typedef {util.mapBehaviors} m ...

"Array.Find function encounters issues when unable to locate a specific string within the Array

Currently, I am utilizing an array.find function to search for the BreakdownPalletID when the itemScan value matches a SKU in the array. However, if there is no match found, my application throws a 'Cannot read property breakdownPalletID of undefined& ...

What is the best way to interpret and execute conditions specified within strings like "condition1 and condition2"?

Received a JSON file from an external source with various conditions that need to be tested, either in real-time or through conversion. Imagine having an instance of a class called Person, with attributes {age: 13, country: "Norway"}, and an ext ...

What does Angular 5 offer in terms of functionality that is equivalent to?

I am working on my AngularJS 1.5 application where I have controllers directly calling service functions. What is the recommended approach to achieve this in Angular? $scope.permissions = ClockingMenuService.permissions; $scope.data = ClockingMenuService ...