typescripttypeofunion-typeskeyof

What does "keyof typeof" mean in TypeScript?


Explain to me what keyof typeof means in TypeScript

Example:

enum ColorsEnum {
    white = '#ffffff',
    black = '#000000',
}

type Colors = keyof typeof ColorsEnum;

The last row is equivalent to:

type Colors = "white" | "black"

But how does it work?

I would expect typeof ColorsEnum to return something like "Object" and then keyof "Object" to not do anything interesting. But I am obviously wrong.


Solution

  • keyof takes an object type and returns a type that accepts any of the object's keys.

    type Point = { x: number; y: number };
    type P = keyof Point; // type '"x" || "y"'
    
    const coordinate: P = 'z' // Type '"z"' is not assignable to type '"x" | "y"'.
    

    typeof with TypeScript types

    typeof behaves differently when called on javascript objects, to when it is called on typescript types.

    type Language = 'EN' | 'ES'; 
    const userLanguage: Language = 'EN';
    const preferences = { language: userLanguage, theme: 'light' };
    
    console.log(typeof preferences); // "object"
    type Preferences = typeof preferences; // type '{language: 'EN''; theme: string; }'
    

    Because the second typeof preferences is in a type expression it is actually TypeScript's own typeof that get called, and not javascript's.

    keyof typeof

    Because keyof is a TypeScript concept we will be calling TypeScript's verion of typeof.

    keyof typeof will infer the type of a javascript object and return a type that is the union of its keys. Because it can infer the exact value of the keys it can return a union of their literal types instead of just returning "string".

    type PreferenceKeys = keyof typeof preferences; // type '"language" | "theme"'