What is the best way to search for an Enum based on its value?

One of my challenges involves an enum containing various API messages that I have already translated for display in the front-end:

export enum API_MESSAGES {
  FAILED_TO_LOAD = 'Failed to load data',
  TOKEN_INVALID = 'Token seems to be invalid',
}

The goal is to utilize the error message received from the back-end to fetch the corresponding translation:

onError: (error: AxiosError<ApiError>) => {
  const errorRes = error.response?.data.error;
  console.log(API_MESSAGES[errorRes])
}

However, attempting this results in the following TypeScript error:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof API_MESSAGES'

No index signature with a parameter of type 'string' was found on type 'typeof API_MESSAGES'

I have explored several options but haven't discovered a straightforward way to access the enum values.

Answer №1

limitations of reverse mappings in string enums

API_MESSAGES[errorRes] triggers an error due to the absence of reverse mappings for string enums, as explained in the Typescript Handbook:

Understanding Reverse Mappings

Numeric enum members possess both forward (name -> value) and reverse (value -> name) mappings, whereas string enum members lack reverse mapping functionality.

A numeric enum compiles into an object containing both forward and reverse mappings.

It's essential to note that string enum members do not receive automatic generation of a reverse mapping.

the importance of ignoring reverse mappings

The primary objective is to showcase the "translated" API message in a human-friendly manner. Even if support existed for string enums within API_MESSAGES[errorRes], the outcome would be:

'Token seems to be invalid' --> TOKEN_INVALID 

This represents the opposite of the desired result.

Furthermore, backend alignment with enum definition simplifies matters!

If the back-end code aligns with the same API_MESSAGES enum, it simply uses "a set of named constants", such as FAILED_TO_LOAD and TOKEN_INVALID, where these values serve as the translated messages themselves.

Hence, serialized API_MESSAGES transmission from the back-end already contains the "translated" message.

Consequently, your onError function becomes:

onError: (error: AxiosError<ApiError>) => {
  const errorRes = error.response?.data.error;
  console.log(errorRes)
}

Therefore, based on Typescript principles and logical deductions, error.response?.data.error holds the type API_MESSAGES. This implies that error.response?.data.error effectively represents the following union type

type API_MESSAGES = 'Failed to load data' | 'Token seems to be invalid',

To reiterate, the translated value already exists. FAILED_TO_LOAD and TOKEN_INVALID merely serve as the Typescript names for those values. In case the back-end mirrors the enum definition.

Alternatively, underlying codes necessitate mapping objects

If FAILED_TO_LOAD and TOKEN_INVALID denote the actual message strings sourced from the backend, employing a mapping object instead of an enum proves beneficial:

export const API_MESSAGES = {
  FAILED_TO_LOAD = 'Failed to load data',
  TOKEN_INVALID = 'Token seems to be invalid',
} as const;

// type API_MESSAGE = 'FAILED_TO_LOAD' | 'TOKEN_INVALID'
export type API_MESSAGE = keyof typeof API_MESSAGES

The error code transmitted from the backend materializes as a plain string, diverging from a typed Enum. The convertServerMessage function showcases the validation and conversion process to the API_MESSAGE enum. As previously mentioned, this activity requires execution at some juncture. Integrating this logic directly into the section of your code responsible for processing the server response and constructing the AxiosError object, wherein AxiosError.response.data.error assumes the type API_MESSAGE, obviates the need for a separate method.

export function convertServerMessage(msg: string): API_MESSAGE {
    if (msg in API_MESSAGES) {
        return msg as API_MESSAGE
    } else {
        // customized error handling can be implemented here
    }
}

Subsequently, the initial onError function operates as intended (refer to endnote):

onError: (error: AxiosError<ApiError>) => {
    // For simplicity, consider relocating the string-to-enum conversion
    // elsewhere within your codebase. It's currently placed here as an example.
    const errorRes = convertServerMessage(error.response?.data.error);
    console.log(API_MESSAGES[errorRes])
}

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

Are there any restrictions on the amount of data that can be included in a Sankey diagram created from an Excel sheet? I would

[please provide a description of the image][1]I am encountering an issue with data limitation in plotting a Sankey diagram from an Excel sheet. I have imported an Excel sheet with 1300 rows of data, but I am only able to plot 12 rows of data. Can anyone pl ...

Working with multiple observables in an array of properties using RXJS

I'm relatively new to using rxjs in my angular projects and I'm facing a challenge with a simple scenario. When making an http call to retrieve a group, it returns data including a list of "buddy ids", "genre ids", and a "region id". In order t ...

Putting VueJS, typescript, and jest to the test: examining the contents of a dropdown list web-component

Currently, I am in the process of testing a dropdown list within a web component utilized in a VueJS application. My main focus is on checking whether the dropdown list actually contains items fetched through an HTTP query (handled in a vuex store) once t ...

Typescript HashMap implementation with Lists as values

Currently delving into TypeScript, I am attempting to generate a collection in a manner akin to the following Java example: HashMap<String, List<String>> hashMap = new HashMap<String,List<String>>(); Struggling to locate any releva ...

Encountering a ReactJs and TypeScript error: "menuItems.map is not a function, issue with map method"

Greetings! I am currently working on implementing the logic of using useState and mapping an array to show only one dropdown item at a time. Below is my array structure with tags (menu name, links (to router), icon (menu icon), and if there are dropdown i ...

Utilizing Angular to parse a JSON string generated with json.dumps

I am having trouble finding a solution that works for me. Currently, I am using python 3.6 (Django Rest Framework) on the server side and Angular 5 on the client side. This is the code on the server: class TypesView(APIView): def get(self,request): ...

Object autofill - Typescript utilizing Angular 5

I am working with an object called "features." Here is an example of the object: [{"_id":"5af03d95c4c18d16255b5ac7","name":"Feature 1","description":"<p>Description</p>\n","neworchange":"new","releaseId":"5aead2d6b28715733166e59a","produc ...

Creating dynamic components from JSON elements does not trigger a rerender of components within an array

Imagine having a simplified input structure like this: [ { type: "text", text: "how are you {name}" }, { type: "input", input: "name" }, { type: "text", text: "good to ...

Utilizing Sharepoint Online SPFX Web parts with React: A guide to selecting scripts dynamically based on environment requirements

Would it be possible for me to dynamically choose which script to utilize in my web component? This is how I currently have my imports set up: import * as jQuery from 'jquery'; import 'jqueryui'; Here's what I am aiming to achie ...

getItemForm does not make a second promise call

I have a scenario where my function calls the api.send service twice, however when I run a test expecting it to resolve both promises, only res1 is returned and not res2. How can I ensure that both promises are resolved successfully? Here is my function: ...

Tips for isolating data on the current page:

Currently, I am using the igx-grid component. When retrieving all data in one call and filtering while on the 3rd page, it seems to search through the entire dataset and then automatically goes back to "Page 1". Is there a way to filter data only within th ...

What is the best approach to have a method in the parent class identify the type based on a method in the child class using TypeScript?

I'm faced with a code snippet that looks like this. class Base{ private getData(): Data | undefined{ return undefined } public get output(): Data | undefined { return { data: this.getData() } } } class ...

Looking to retrieve the request body in a route handler in Next.js version 13.2?

I encountered an issue while attempting to send a post request to my API. The problem arises when I try to access the request body within the route handler, resulting in the following error: Code: export async function POST(request: Request) { const ...

Comparing TypeScript and C++ in terms of defining class reference member variables

class B; class A { A(B b_) : b{b_} {} B &b; }; In C++, it is possible to have a reference member variable like 'b' in class A. Can the same be achieved in TypeScript? Alternatively, is there a specific method to accomplish this in ...

IE11 and how it handles Typescript and promises

Currently, I am utilizing Typescript version 2.4.2 along with Webpack for compilation purposes. Despite successful compilation, when running my code on IE11, an error 'Promise' is undefined arises. Below is a glimpse of my tsconfig: { "comp ...

Break down and extract elements using typedEvent in TypeScript

Within the external library, there is the following structure: export interface Event extends Log { args?: Result; } export interface TypedEvent<EventArgs extends Result> extends Event { args: EventArgs; } export type InstallationPreparedEven ...

Matching multiline input with RegExp and grouping matches from consecutive lines

Imagine having a text file with the following content: AAAA k1="123" k2="456" several lines of other stuff AAAA k1="789" k2="101" AAAA k1="121" k2="141" The objective is to extract the values of k1 and k2 while keeping them grouped together. For instance ...

The Angular 13 application encounters a "moment is not a function" error after importing an Angular 13 package

Upgrading a private library named privLib to Angular 13 has been my recent task in order to facilitate the migration of all other projects. However, an issue arises when this library is imported into another project where one of the services utilizes momen ...

Mastering the utilization of API routes within the Next JS 13 App Router framework

As a newcomer to React JS and Next.js, I recently made the switch from using the Page Router API in Next.js to utilizing the new App Router introduced in Next.js 13. Previously, with the Page Router, creating a single GET request involved nesting your "JS ...

Ways to input a return value that may be an array depending on the input

I'm struggling to properly type the return value in TypeScript to clear an error. function simplifiedFn( ids: string | string[], ): typeof ids extends string[] ? number[] : number { const idsIsArray = Array.isArray(ids); const idsProvided = idsI ...