DEV Community

Deniz Akşimşek
Deniz Akşimşek

Posted on • Originally published at denizaksimsek.com on

Iota (from Golang) in JavaScript

(Skip to code)

Enums in Javascript

Currently, the ways we create enums include

  • String literals (see addEventListener), which can be typed with TypeScript, but look a bit ugly

    type Direction = 'north' | 'east' | 'south' | 'west'
    
  • TypeScript enums

    enum Direction { north, east, south, west }
    
  • Integer constants, IMO your best option if you’re not using TypeScript

    const Directions = { north: 0, east: 1, south: 2, west: 3 }
    

Enums in Go [1]

Go doesn’t have enums, but an unusual keyword iota:

type Direction int
const (
    North Direction = iota
    East
    South
    West
)
Enter fullscreen mode Exit fullscreen mode

There’s something subtle going on here. The iota relies on a few Go features:

  • When multiple const declarations are grouped together, the right hand side is implicitly repeated
  • Iota is incremented every time it is evaluated, and reset with each const

My JavaScript shorthand is nowhere near as magical… but it does make use of proxies.

function iota(start = 0) {
    let count = start
    return new Proxy({}, {
        get(o, prop) {
            if (prop in o) return o[prop]
            else return o[prop] = count++
        }
    })
}

const { north, east, south, west } = iota()
console.log(north)
Enter fullscreen mode Exit fullscreen mode

So, is this function any good?

For one, it lacks some of Go’s iota capabilities — you can’t create bitmasks with this the way you would in Go with 1 << iota. We could augment it a bit by accepting a callback:

function iota(cb = (i => i)) {
    let count = 0
    return new Proxy({}, {
        get(o, prop) {
            if (prop in o) return o[prop]
            else return o[prop] = cb(count++)
        }
    })
}

// flag bits
const { hasPermissionFlag, userModeFlag, useLegacyProtocolFlag } = iota(i => 1 << i)
const hasPermission = options & hasPermissionFlag
Enter fullscreen mode Exit fullscreen mode

I don’t think bitmasks are very common at all in JavaScript code, though.

A more significant setback is that you can’t get a list of all the enum values — nothing we can’t fix:

function iota(start = 0) {
    let count = start
    let firstProp = true
    return new Proxy({}, {
        get(o, prop) {
            if (firstProp) {
                firstProp = false
                return { // Enum descriptor
                    get values() { return o }
                }
            }
            if (prop in o) return o[prop]
            else return o[prop] = count++
        }
    })
}

const { Direction, north, east, south, west } = iota()
console.log(Direction)
Enter fullscreen mode Exit fullscreen mode

This is open for extension — we could add more methods on the enum description such as converting the integer value of a Direction to its name, or validating a Direction that we parsed from a config file.

I might have a metaprogramming addiction.


  1. Initially I wasn’t going to bring Go into this at all. However, it turns out enum is a reserved word in JS, so I went with iota for the name of the function, and felt the need to explain it. ↩︎

Discussion (0)