1

Whenever I have a union type of strings in TypeScript, a very common thing I need to do is get an array of these string literals.

export type UserPersona =
    | "entrepreneur"
    | "programmer"
    | "designer"
    | "product_manager"
    | "marketing_sales"
    | "customer_support"
    | "operations_hr"

I find it a bit cumbersome, but whenever I need to do this, I will create an object map, type everything out again, and then get the key can cast the type.

const userPersonaMap: { [key in UserPersona]: true } = {
    entrepreneur: true,
    programmer: true,
    designer: true,
    product_manager: true,
    marketing_sales: true,
    customer_support: true,
    operations_hr: true,
}

export const userPersonas = Object.keys(userPersonaMap) as Array<UserPersona>

A few things I don't like about this approach:

  1. I have to type everything out twice.
  2. I have to cast the type.
  3. There's runtime overhead - granted, its trivial, but I do this all the time.
Chet
  • 18,421
  • 15
  • 69
  • 113

1 Answers1

0

This doesn't answer the question directly, but offers a different solution to get the same result.

/**
 * Creates a string enum. Use like so:
 *     const Ab = strEnum(['a', 'b']);
 *     type AbKeys = keyof typeof Ab;
 * @param keys keys in the enum
 * @returns enum object
 */
export function createStringEnum<T extends string>(keys: T[]): {[K in T]: K} {
    return keys.reduce((res, key) => {
        res[key] = key;
        return res;
    }, Object.create(null));
}

const Ab = createStringEnum(['a', 'b']);
console.log(Object.keys(Ab)); // ['a','b']
console.log(Ab.a) // 'a'

type AbKeys = keyof typeof Ab;
const a: AbKeys = 'c'; // error
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217