typescriptenumstypescript-generics

How to get next (or previous) enum value in Typescript


I have an enum which is defined like this:

enum Ed {
  up,
  down,
  left,
  right,
}

//or 

enum Es {
  A = "a",
  B = "b",
  C = "c",
}

So given value Es.B, I want to get the next one which is Es.C

Something like Es.B+1 or getNextEnum(Es.B) or EnumX.of(Es).next(Es.B) or even simpler? Function should support any enum, so no hardcoded values please.

Note: Next of last element is expected to be the first element of enum.

Thanks


Solution

  • Here is the answer which works for both numeric and string enums:

    class EnumX {
      static of<T extends object>(e: T) {
        const values = Object.values(e)
        const vLen = values.length
        const isNumEnum = e[e[values[0]]] === values[0]
    
        return isNumEnum ? {
          next: <K extends keyof T>(v: T[K]) => values[(values.indexOf(v) + 1) % (vLen / 2) + vLen / 2],
          prev: <K extends keyof T>(v: T[K]) => values.at((values.indexOf(v) - 1) % (vLen / 2) + vLen / 2)
        } : {
          next: <K extends keyof T>(v: T[K]) => values[(values.indexOf(v) + 1) % vLen],
          prev: <K extends keyof T>(v: T[K]) => values.at((values.indexOf(v) - 1) % vLen)
        }
      }
    }
    

    This also provides functions for both next and previous values.

    TS PLayground

    Usage example:

    enum Es {
      A = "a",
      B = "b",
      C = "c",
    }
    const esx = EnumX.of(Es)
    console.log(esx.next(Es.A), esx.next(Es.B), esx.next(Es.C)); // "b",  "c",  "a" 
    console.log(esx.prev(Es.A), esx.prev(Es.B), esx.prev(Es.C)); // "c",  "a",  "b" 
    
    enum En {
      A,
      B,
      C,
    }
    
    const enx = EnumX.of(En)
    console.log(enx.next(En.A), enx.next(En.B), enx.next(En.C));  // 1,  2,  0 
    console.log(enx.prev(En.A), enx.prev(En.B), enx.prev(En.C));  // 2,  0,  1 
    

    Thanks @alx for inspiration