My JS enum type

For my PersonSection widget I needed to have a PERSON_TYPES constant.

var PERSON_TYPES = ['juridică', 'fizică'];

This turned out handy when building the SelectField that’ll let the user pick any of the two options.

And then in some other place I had an if/else that was supposed to display a different set of fields depending on the option selected, so I needed something like this:

if (selectedOption === ???)

So now I had the option to either use the string:

if (selectedOption === 'juridică')

or,

if (selectedOption === PERSON_TYPES[0])

I didn’t like either of them, so I decided to add to the PERSON_TYPES array one property per option to hold the value and still have it as a constant to use elsewhere in the code:

PERSON_TYPES.COMPANY = 'juridică';
PERSON_TYPES.INDIVIDUAL = 'fizică';

so now I can say

if (personType === PERSON_TYPES.INDIVIDUAL) // 

Looks good here, but now I had this:

var COMPANY = 'juridică';
var INDIVIDUAL = 'fizică';
var PERSON_TYPES = [COMPANY, INDIVIDUAL];
PERSON_TYPES.COMPANY = COMPANY;
PERSON_TYPES.INDIVIDUAL = INDIVIDUAL;

which wasn’t intention-revealing so I packed it into a function:

// somewhere at the top
var PERSON_TYPES = definePersonTypes();

// more code

// somewhere at the bottom
function definePersonTypes() {
  var COMPANY = 'juridică';
  var INDIVIDUAL = 'fizică';

  var types = [COMPANY, INDIVIDUAL];
  types.COMPANY = COMPANY;
  types.INDIVIDUAL = INDIVIDUAL;

  return types;
}

This worked. But later I got to the CaseSubjectSection widget and I needed a similar thing for SUBJECT_TYPES so I extracted a utility function:

function createHashArray(hash) {
  var array = _.values(hash);

  _.each(hash, function(v, k) {
    array[k] = v;
  });

  return array;
}

var PERSON_TYPES = createHashArray({
  COMPANY: 'juridică',
  INDIVIDUAL: 'fizică'
});

The createHashArray name didn’t sound right. I squinted at it a little bit and looked a bit like enum types, so I renamed it to createEnumArray. Still not perfect, but I think it reveals enough of the intent.

Later when writing unit tests the deepEqual was surprisingly failing here:

t.deepEqual(createdEnum, ['juridică', 'fizică'], 'the array has the appropriate items');

I didn’d check the source code for deepEqual but my guess was that it’s picking on the COMPANY and INDIVIDUAL properties on the PERSON_TYPES array, which are not on the vanilla selectOptionLabels. I tried to transform them both to strings with .join(',') and then do the assertion based on that. It worked but it was making the test harder to understand.

To get around this, I made the properties non-enumerable by using Object.defineProperty instead of array[k] = v, and now I have this:

function createEnumArray(hash) {
  var array = _.values(hash);

  _.each(hash, function(v, k) {
    Object.defineProperty(array, k, {
      value: v,
      enumerable: false
    });
  });

  return array;
}

var PERSON_TYPES = createEnumArray({
  COMPANY: 'juridică',
  INDIVIDUAL: 'fizică'
});

It’s a little more verbose, but it gives me a cleaner test, and I accept it.