Search code examples
typescriptunion-types

Map all tags of a tagged union type in TypeScript


Is it possible to map all tags of a tagged union type into an array? Let's say we have the following types:

type Options = Cash | PayPal | CreditCard;    

interface Cash {
  kind: "cash";
}

interface PayPal {
  kind: "paypal";
  email: string;
}

interface CreditCard {
  kind: "credit";
  cardNumber: string;
  securityCode: string;
}

Is it possible to collect all discriminators kind into a string array? The result should be something like ['cash', 'paypal', 'credit'].

Thank you in advance!


Solution

  • There is no way to get values from a type in standard typescript (there might be some unofficial extensions to the language that allow this)

    You can get a type that is a union of all kinds:

    type OptionsKind = Options['kind'] //  "cash" | "paypal" | "credit"
    

    You can also build an object that MUST have all properties of the union and use Object.keys to get an array from this object:

    type OptionsKind = Options['kind'] //  "cash" | "paypal" | "credit"
    let OptionsKind: { [P in OptionsKind]: 1 } = {
        cash: 1,
        credit: 1,
        paypal: 1        
    }
    let OptionsKindArray = Object.keys(OptionsKind);
    

    This solution will ensure that you get an error if you have any extra keys in the object, if you don't have all keys in the object and if you misspelled any keys. So basically it ensures that the duplicate data is at least always up to date.

    You could even make a helper function for any union:

    type OptionKinds = Options['kind'] //  "cash" | "paypal" | "credit"
    function unionValues<T extends string>(o: Record<T, 1>) {
        return Object.keys(o) as T[];
    }
    
    let OptionKinds = unionValues<OptionKinds>({ cash: 1, paypal: 1, credit: 1 });