41

So I have this in the javascript for my page:

var TEST_ERROR = { 'SUCCESS' : 0, 'FAIL' : -1, 'ID_ERROR' : -2 }; 

And perform tests on functions in the page like so:

function test() { // Get the paragraph from the DOM var testResultParagraph = document.getElementById('testResult'); // Check the paragraph is valid if(!testResultBox) { // Update the web page testResultParagraph.value = TEST_ERROR.ID_ERROR; return TEST_ERROR.ID_ERROR; } // Something to store the results var testResult = TEST_ERROR.SUCCESS; // Test the calculation testResult = testCalculate() // Update the web page testResultParagraph.value = testResult; // The test succeeded return TEST_ERROR.SUCCESS; } 

The result of testCalculate() and the value of the paragraph will be either 0, -1, -2 depending on the outcome.

Now I want to map this to a string so that the paragraph shows 'Success', 'Fail' or 'ID Error'

I could do this a few ways I have figured:

var TEST_ERROR = { 'SUCCESS' : {VALUE : 0 , STRING: 'Success' }, 'FAIL' : {VALUE : -1, STRING: 'Fail' }, 'ID_ERROR' : {VALUE : -2, STRING: 'Id Error'}, }; 

would require a modification to the enum dot accessors, or

var TEST_ERROR = { 'SUCCESS' : 0, 'FAIL' : 1, 'ID_ERROR' : 2 }; var TEST_STRING = [ 'Success', 'Fail', 'ID Error' ]; 

Which would require changes to the logic (result > TEST_ERROR.SUCCESS seems wierd tho!)

My question is how would you go about mapping an enumerator value to a string value in Javascript? I'm thinking the second way is the most sensible, but would like the enumerator to be positive for successes and negative for fails. I also like the idea of the first containing the strings and values in the object structure.

Any ideas?

Thanks!

Matt

PS. I'm going to be doing the testing in a Web Worker, so that the page doesn't hang and the results will be put into a table, not a paragraph like above.

PPS. I'm pretty new to Javascript programming, but do a lot in ASM, C, C++, C#.

1
  • Thanks for the answers, I'm pretty early on in this project so will accept an answer but not sure which direction I'll be going at the moment.CommentedNov 26, 2010 at 17:13

11 Answers 11

51

Do you actually need the numeric values at all? If not then you could use something like this:

const TEST_ERROR = { SUCCESS : 'Success', FAIL : 'Fail', ID_ERROR : 'ID Error' }; Object.freeze(TEST_ERROR) 
3
  • I like this it's nice and simple. I could just do if(result != TEST_ERROR.SUCCESS) and use your answer. Let me have a think to see if I'm going to need any other pass states other that TEST_ERROR.SUCCESS.CommentedNov 26, 2010 at 17:01
  • Can the inner keys and/or values be accidentally modified? How to fix them as constants or raise an error in case modification is attempted? This is a potential issue, it seems.CommentedSep 30, 2019 at 19:23
  • 1
    Yes, you're right. you can use Object.freeze(TEST_ERROR). I think It'll not throw an error for modification but It ignores the modification. So the purpose fulfilled.
    – Orilious
    CommentedJul 7, 2020 at 3:28
33

Not quite optimal, but the cleanest you can get without pre-computing the reverse dictionary (and besides, this shouldn't be too much of an issue if you only have a few enumeration values):

function string_of_enum(enum,value) { for (var k in enum) if (enum[k] == value) return k; return null; } 
2
  • 3
    Works great ! This should be the accepted answer, works for any enum, no limitations.
    – Alex
    CommentedJan 10, 2015 at 12:33
  • 1
    This is my choice as I need both the numeric value to pass back to the server and the text value to display to the user. Thanks for this.CommentedDec 5, 2018 at 20:30
24

For TypeScript, there is a simpler solution (Please ignore my answer if you stick with JS):

export enum Direction { none, left = 1, right = 2, top = 4, bottom = 8 } export namespace Direction { export function toString(dir: Direction): string { return Direction[dir]; } export function fromString(dir: string): Direction { return (Direction as any)[dir]; } } console.log("Direction.toString(Direction.top) = " + Direction.toString(Direction.top)); // Direction.toString(Direction.top) = top console.log('Direction.fromString("top") = ' + Direction.fromString("top")); // Direction.fromString("top") = 4 console.log('Direction.fromString("xxx") = ' + Direction.fromString("unknown")); // Direction.fromString("xxx") = undefined 

Because the enumeration type is compiled into an object(dictionary). You don't need a loop to find the corresponding value.

enum Direction { left, right } 

is compiled into:

{ left: 0 right: 1 0: "left", 1: "right" } 
4
  • 2
    That's TypeScript. This is tagged with JavaScript.CommentedApr 22, 2020 at 11:11
  • 3
    This actually helped me in JS. Didn't know you could use integers as object keys. Now I can map both directions using my "enum" object from Object.freeze({...});CommentedSep 17, 2020 at 20:05
  • 1
    Yup, this was a question about JavaScript, but this TypeScript script was incredibly useful to me - thanks ! I didn't know we could do this... amazing!CommentedDec 22, 2020 at 8:29
  • In my case, TS was not transpiling it but in combination with: stackoverflow.com/a/63574739/5811471 it works like a charm. ThanksCommentedFeb 5, 2021 at 10:48
11

I prefer the below method.

enum ColorEnum { Red, Green, Blue } console.log(ColorEnum[ColorEnum.Red]); 
1
  • I thought this was not going to work but It did, really good solution thanks!CommentedMay 2, 2022 at 19:36
3

You could always have the values be objects of a particular type.

var TEST_ERROR = (function() { function ErrorValue(value, friendly) { this.value = value; this.friendly = friendly; } ErrorValue.prototype = { toString: function() { return this.friendly; }, valueOf: function() { return this.value; } }; return { 'SUCCESS': new ErrorValue(0, 'Success'), 'FAIL': new ErrorValue(1, 'Fail'), 'ID_ERROR': new ErrorValue(2, 'ID error') }; })(); 

Now when you get a value of that type:

var err = testFunction(whatever); 

you can get the string value with

alert(err.toString()); 

In fact you shouldn't even have to call .toString() explicitly, most of the time.

1
  • Good, seems sensible building in a .toString() for the enumerator object. I'm just getting started with this so will need to have a think if I need this over LukeH solution.CommentedNov 26, 2010 at 17:04
2

If you are typescript, then you will already have a definition for the enum. Else you can directly use the JS version of the enum.

var Status; (function (Status) { Status[Status["New"] = 0] = "New"; Status[Status["Submitted"] = 1] = "Submitted"; Status[Status["Approved"] = 2] = "Approved"; Status[Status["Rejected"] = 3] = "Rejected"; })(Status || (Status = {})); var snew = Status.New; console.log(snew); //This is the number console.log(Status[snew]); //This is the string 
1
2

The best way to do it is:

export const UserLevel = Object.freeze({ BABY: 1, CHILED: 2 }); 

We need to add freeze, even though UserLevel is const, because we can change the values inside. freeze will make the "enum" safe from changes.

    0

    This might be different from what you want but I want to share my answer. This was inspired by @LukeHconst solution. Consider bookCategory below you will notice that I'm using a number as a key.

    const bookCategory = { "0": "Biography", "1": "Fiction", "2": "History", "3": "Mystery", "4": "Suspense", "5": "Thriller" }; 

    I wrote the bookCategory like this because if you are using an enum column in MySQL. For example,

    category ENUM ('0', '1', '2', '3', '4', '5') 

    You would need some kind of conversion in JavaScript. So I came up with this and the usage is simple as:

    bookCategory[book.category] 
      0

      If you're using TypeScript and don't need the numeric values, you can map directly to string values like this:

      enum TEST_ERROR { SUCCESS = 'Success', FAIL = 'Fail', ID_ERROR = 'ID Error' } 

      Source: https://www.typescriptlang.org/docs/handbook/enums.html#string-enums

        0

        Other answers fail to address a scenario where the Enum is a compound word(like InProgress) and you want to convert it to constant(In Progress) keeping the number indexing in enum.

        enum Status{ Success Failure, InProgress } const STATUS_DICTIONARY = { [Direction.Success] :'Success', [Direction.Failure]:'Failure', [Direction.InProgress]:'In Progress', } console.log(STATUS_DICTIONARY[Status.InProgress]) //"In Progress" 

        This answer has more details

        I needed this scenario when I wanted to show this enum in the UI as proper & meaningful English text to user.

          -1

          Building on Victor's excellent answer, so it works in TypeScript:

          enumToStr(enumeration: any, value: any): string { for (var k in enumeration) if (enumeration[k] == value) return <string>k; return null; } 

            Start asking to get answers

            Find the answer to your question by asking.

            Ask question

            Explore related questions

            See similar questions with these tags.