61

As said in the title, how can you determine the number of elements in a enum in Typescript such as in this example

enum ExampleEnum {

    element1 = 1,
    element2 = 2,
    element3 = 3,
    element4 = 4,
    element5 = 5,
    element6 = 6

}

var exampleEnumElementCount:number = ? 

How would the count be determined? In this case it should be 6

ToddBFisher
  • 11,370
  • 8
  • 38
  • 54

4 Answers4

110

Typescript does not provide a standard method to get the number of enum elements. But given the the implementation of enum reverse mapping, the following works:

Object.keys(ExampleEnum).length / 2;

Note, for string enums you do not divide by two as no reverse mapping properties are generated:

Object.keys(StringEnum).length;

Enums with mixed strings and numeric values can be calculated by:

Object.keys(ExampleEnum).filter(isNaN).length;
Vočko
  • 2,478
  • 1
  • 23
  • 31
Zen
  • 5,065
  • 8
  • 29
  • 49
  • 6
    Why divide by 2? – El Dude May 05 '17 at 22:10
  • 6
    This answer is dangerous. It will fail for string enums. – Markus Ende Jan 19 '18 at 07:32
  • 3
    This answer is not correct anymore. `Object.keys(ExampleEnum) / 2` does not need to be divided by two as of now. With Typescript v3 even strings are well supported, exactly like numbers. @MarkusEnde – Ilker Cat Dec 26 '18 at 17:49
  • 10
    @IlkerCat Nothing has changed regarding that problem in TypeScript v3 - enums with numbers still have twice as much keys, since they get a reverse mapping, while string enums do not get a reverse mapping, so you don't need to divide by two. This difference in runtime implementation was always there and still exists. Note that you can also have mixed enums. In that case the number of enum members is somewhere in between the half and full length and can be exactly calculated with Object.keys(ExampleEnum).filter(isNaN).length (you can also use Object.values here), counting only non-numeric items. – Cito Mar 27 '19 at 09:34
  • Doesn't work for `const enum`s, since you need to call `Object.keys` – DexieTheSheep May 11 '23 at 19:19
32

If you have an enum with numbers that counts from 0, you can insert a placeholder for the size as last element, like so:

enum ERROR {
  UNKNOWN = 0,
  INVALID_TYPE,
  BAD_ADDRESS,
  ...,
  __LENGTH
}

Then using ERROR.__LENGTH will be the size of the enum, no matter how many elements you insert.

For an arbitrary offset, you can keep track of it:

enum ERROR {
  __START = 7,
  INVALID_TYPE,
  BAD_ADDRESS,
  __LENGTH
}

in which case the amount of meaningful errors would be ERROR.__LENGTH - (ERROR.__START + 1)

steabert
  • 6,540
  • 2
  • 26
  • 32
7

The accepted answer doesn't work in any enum versions that have a value attached to them. It only works with the most basic enums. Here is my version that works in all types:

export function enumElementCount(enumName: any): number {
    let count = 0
    for(let item in enumName) {
        if(isNaN(Number(item))) count++
    }
    return count
}

Here is test code for mocha:

it('enumElementCounts', function() {
    enum IntEnum { one, two }
    enum StringEnum { one = 'oneman', two = 'twoman', three = 'threeman' }
    enum NumberEnum { lol = 3, mom = 4, kok = 5, pop = 6 }
    expect(enumElementCount(IntEnum)).to.equal(2)
    expect(enumElementCount(StringEnum)).to.equal(3)
    expect(enumElementCount(NumberEnum)).to.equal(4)
})
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
4

To further expand on @Esqarrouth's answer, each value in an enum will produce two keys, except for string enum values. For example, given the following enum in TypeScript:

enum MyEnum {
    a = 0, 
    b = 1.5,
    c = "oooo",
    d = 2,
    e = "baaaabb"
}

After transpiling into Javascript, you will end up with:

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["a"] = 0] = "a";
    MyEnum[MyEnum["b"] = 1.5] = "b";
    MyEnum["c"] = "oooo";
    MyEnum[MyEnum["d"] = 2] = "d";
    MyEnum["e"] = "baaaabb";
})(MyEnum || (MyEnum = {}));

As you can see, if we simply had an enum with an entry of a given a value of 0, you end up with two keys; MyEnum["a"] and MyEnum[0]. String values on the other hand, simply produce one key, as seen with entries c and e above.

Therefore, you can determine the actual count by determining how many Keys are not numbers; ie,

var MyEnumCount = Object.keys(MyEnum).map((val, idx) => Number(isNaN(Number(val)))).reduce((a, b) => a + b, 0);

It simply maps through all keys, returning 1 if the key is a string, 0 otherwise, and then adds them using the reduce function.

Or, a slightly more easier to understand method:

var MyEnumCount = (() => {
    let count = 0;
    Object.keys(MyEnum).forEach((val, idx) => {
        if (Number(isNaN(Number(val)))) {
            count++;
        }
    });
    return count;
})();

You can test for yourself on the TypeScript playground https://www.typescriptlang.org/play/

sme
  • 4,023
  • 3
  • 28
  • 42