How to set an object property value to its own variable name (during initialization if possible)?

140 views Asked by At

question

How to set an object property value to its own variable name (during initialization if possible)?

eg

For example, to create a Enum (inside class AA) in Javascript:

class AA {
  static Color = {
    Red: 'Red', 
    Green: 'Green', 
    Blue: 'Blue', 
  }
}

I have to repeat the String name everytime.

Is there a simpler way to do this, something like eg:

class AA {
  static Color = {
    Red: this.currentProperty.name, 
    Green: this.currentProperty.name, 
    Blue: this.currentProperty.name, 
  }
}

requirements (not mandatory) & comments

  • Please make this As Simple As Possible (dont be complicated/cumbersome).

    • (The hardest requirement. It would be best in the form shown above (during initialization).
    • I may be a bit picky on this... (I know this is very subjective, and such thing may not even exist)
    • though, any other thoughts are still welcome)
  • The variable value & variable name can be refactored at the same time -- without the need to change them separately.

  • It doesnt have to be an Enum (-- this topic is not limited to Enum only, a normal object will do)

  • Try to use Es6+

  • Try to let Jsdoc able to recognize this as an Enum (maybe the use of @emun (?<)), (mainly for autocompletion / Type hint on Vscode)

  • Try to let Debugger able to recognize this as an Enum & able to view the value as a meaningful string

  • Im aware of there are some Enum lib in github eg, not sure they are good enough / fit my style.

  • Im aware of the use of Symbol() on Enum

  • Im aware of need to make Enum immutable (private + getter / Object.freeze)

  • I dont think Object.keys() can help. (too cumbersome?)

1

There are 1 answers

8
Andrew Parks On

class AA {
  static Color = Object.fromEntries(['Red','Green','Blue'].map(i=>[i,i]))
}
console.log(AA.Color)

or, with a helper method:

function makeEnum(...props) { return Object.fromEntries(props.map(i=>[i,i])) }

class AA {
   static Color = makeEnum('Red','Green','Blue')
}

console.log(AA.Color)

this might help with autocompletion:

function makeEnum(obj) { return Object.fromEntries(Object.keys(obj).map(i=>[i,i])) }

class AA {
   static Color = makeEnum({Red:'', Green:'', Blue:''})
}

console.log(AA.Color)

or using a proxy:

function makeEnum() {
  let o = {}, p = new Proxy(o, {get:(_,i)=>(i==='enum'?o:(o[i]=i,p))})
  return p
}

class AA {
  static Color = makeEnum().Red.Green.Blue.enum
}

console.log(AA.Color)

including Object.freeze() to prevent reassignment:

function makeEnum() {
  let o = {}, p = new Proxy(o, {get:(_,i)=>
    (i==='enum'?(Object.freeze(o),o):(o[i]=i,p))})
  return p
}

class AA {
  static Color = makeEnum().Red.Green.Blue.enum
}

console.log(AA.Color)
AA.Color.Red = 'Yellow'
console.log(AA.Color)

another proxy variant: the new keyword is used to trigger freezing of the object:

function Enum() {
  let o={}, p = new Proxy(function() {}, {
    construct: () => (Object.freeze(o),o),
    get:(_,i)=>(o[i]=i,p)
  });
  return p;
}

class AA {
  static Color = new (Enum().Red.Green.Blue)
}

console.log(AA.Color)
console.log(AA.Color.Red)
AA.Color.Red = 'Yellow' // frozen object can't be changed
console.log(AA.Color.Red)
AA.Color.Orange = 'Orange' // frozen object can't accept new properties
console.log(AA.Color)