DEV Community

Cover image for String-literal Union Types to Array - or - How to kick Pluto out of the list of planets
Jonathan Schneider
Jonathan Schneider

Posted on • Edited on

String-literal Union Types to Array - or - How to kick Pluto out of the list of planets

Pluto! Once a member of our own solar system's list of 9 planets, is now considered a dwarf planet. Who thought that list would change? And if Pluto is ever re-considered to be more than a dwarf, what happens to Planet Nine's name?

Similar to our solar system, we sometimes expect that some code or master data doesn't change. But when it does,

  • ["Pluto"] is often hardcoded in arrays for dropdown-lists etc.
  • {"Pluto": {"discovered":1930, "namedAfter": "Pluto"}} can be found in keys or values of complex json objects
  • or it is a parameter of a function getLegendFromMythologyByDeity(f: "Pluto" | "Flora" | "Juno" | "Apollo" | "Minerva" | "Diana" | "Vulcan" | "Sol").

Image description

So to improve the situation, we can fill these types by hand. They're called string literal types, more on that topic here:

export type PlanetsType: "Mercury" | "Venus" | "Earth" | "Mars" | "Jupiter" | "Saturn" | "Uranus" 
  | "Neptune"; 
  //| "Pluto";
export type MythologicalDeityType: "Pluto" | "Flora" | "Juno" | "Apollo" | "Minerva" | "Diana" | "Vulcan" | "Sol";
export type MickeysFriendsType: "Pluto" | "Minnie" | "Donald";
Enter fullscreen mode Exit fullscreen mode

If you additionally want an array that contains all possible permutations of a string literal union type, you could fill that by hand:

export const PlanetsTypeKeys: PlanetsType[] = [
  "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus"
  , "Neptune"];
Enter fullscreen mode Exit fullscreen mode

...but you would have to remember to update that each time a new string literal type enters that union.

export type PlanetsType: "Mercury" | "Venus" | "Earth" | "Mars" | "Jupiter" | "Saturn" | "Uranus" 
  | "Neptune" 
  | "Planet9TheMisterious"; // <-- the new one, now the array has to be updated
Enter fullscreen mode Exit fullscreen mode

A self-sustaining solution

Remembering to update the "right part" of the code is usually hard, even if you leave a comment. Throwing type errors is thus much better - and because we can't create an Array (runtime - javascript) from a union type (compile time - typescript), we'll use a helper, that'll finally bring us back to the master data.

/**
 * PlanetsType is a union type of string literals. This is useful for making switch-case statements exhaustive:
 * https://www.typescriptlang.org/docs/handbook/2/narrowing.html#exhaustiveness-checking
 * 
 * below however, we want to get an exhaustive list of all string literals in the union type. By building a helper
 * object with the key set to "s in PlanetsType", we effectively create an enum-like structure with all the
 * string literals of PlanetsType. When you create or change PlanetsType, this helps to keep the 
 * array in PlanetsTypeKeys up-to-date by throwing a typing error. The order of the entries is also preserved
 */
const PlanetsTypeHelperObj: { [s in PlanetsType ]: PlanetsType } = {
  "Mercury":"Mercury",
  "Venus":"Venus",
  "Earth":"Earth",
  "Mars":"Mars",
  "Jupiter":"Jupiter",
  "Saturn":"Saturn",
  "Uranus":"Uranus",
  "Neptune":"Neptune",
  //"Pluto":"Pluto",
  "Planet9TheMisterious":"Planet9TheMisterious",
}

export const PlanetsTypeKeys: PlanetsType[] = Object.keys(PlanetsTypeHelperObj) as PlanetsType[]
Enter fullscreen mode Exit fullscreen mode

This turns PlanetsTypeKeys into an exhaustive Array of string literals in typescript. Because it's based on a json object (also called "dictionary" in this usage), there are no duplicates. Finally, the value-side of the json object ({"VenusKey":"VenusValue"}) can be anything you like. If you'd like to make the value-part your master data, the PlanetsTypeKeys will stay up to date, ready to be used ... with a dropdown for example.

Image description

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay