Search code examples
typescriptenumstypeof

How to reference the type of an enum using only a variable containing the enum


A third-party library exports a variable containing an enum instead of the enum itself:

enum Size { S, M, L }
export const sizeType: typeof Size = Size;

In my own code, how can I declare that something has type Size?

import { sizeType } from '...';

interface Props {
    size: /* What goes here that's equivalent to 'Size'? */
}

const props: Props = { size: sizeType.S };
props.size = sizeType.L;

Here are some declarations I tried that don't work:

size: typeof sizeType;
// error: Type 'Size' is not assignable to type 'typeof Size'.

size: typeof sizeType['S'];
// error: Type 'Size.L' is not assignable to type 'Size.S'.

size: InstanceType<typeof sizeType>;
// error: Type `typeof Size' does not satisfy the constraint 'abstract new (...args: any) => any`.

Solution

  • Since you don't have access to the enum, the only option will be to get the type of the values of the enum by using the sizeType:

    // typeof Size
    type Case1 = typeof sizeType
    // typeof Size
    type Case2 = typeof Size
    

    Now, by using the indexed access let's get the type of every value in union format:

    // Size
    type Case3 = typeof sizeType[keyof typeof sizeType]
    // Size
    type Case4 = typeof Size[keyof typeof Size]
    

    With the enums, the whole thing looks a bit weird and that's why I personally prefer to use const assertion + the satisfies operator on javascript object:

    const SIZE =  {
      S :0,
      M: 1,
      L: 2,
    } as const satisfies Record<string, number>
    

    Anyway, moving back to the problem, let's test the type that we got in the last cases:

    const case3A: Case3 = Size.S
    const case3B: Case3 = 'error' // error
    
    const case4A: Case4 = Size.S
    const case4B: Case4 = 'error' // error
    

    Looks good!

    Usage:

    interface Props {
      size: typeof sizeType[keyof typeof sizeType];
    }
    

    If you would like to shorten the code, you could use the ValueOf utility type described in this answer:

    type ValueOf<T> = T[keyof T];
    
    interface Props {
      size: ValueOf<typeof sizeType>;
    }