Explaining the video "Enums Considered Harmful" of Matt Pocock

Fredy Sandoval - Dec 18 '22 - - Dev Community

I was watching this video by Matt Pocock, but I found really hard to digest and internalize the TypeScript, so I decided to create a little guide, because I learn better when I explain things to others, so here it is.
The TypeScript shown in the video

const LOG_LEVEL = {
   DEBUG: 'debug',
   WARNING: 'warning',
   ERROR: 'error',
} as const;

type ObjectValues<T> = T[keyof T];
type LogLevel = ObjectValues<typeof LOG_LEVEL>
Enter fullscreen mode Exit fullscreen mode

Destructuring...

'typeof' will get you the types

type LOG_LEVEL_TYPE = typeof LOG_LEVEL;
// Hardcoded will be like this:
type LOG_LEVEL_TYPE_2 = {
    readonly DEBUG: "debug";
    readonly WARNING: "warning";
    readonly ERROR: "error";
}
Enter fullscreen mode Exit fullscreen mode

'keyof' will get the keys

type LOG_LEVEL_KEYS = keyof LOG_LEVEL_TYPE;
// Hardcoded will be like this:
type LOG_LEVEL_KEYS_2 = "ERROR" | "WARNING" | "DEBUG"
Enter fullscreen mode Exit fullscreen mode

'type[i]' will get the values

type LOG_LEVEL_VALUES = LOG_LEVEL_TYPE["ERROR" | "WARNING" | "DEBUG"];
// or
type LOG_LEVEL_VALUES_2 = LOG_LEVEL_TYPE[LOG_LEVEL_KEYS];
// Hardcoded will be like this:
type LOG_LEVEL_VALUES_3 = "debug" | "warning" | "error"
Enter fullscreen mode Exit fullscreen mode

For example the variable myLog can only be the VALUES, anything else will throw an error

let myLog: LOG_LEVEL_VALUES;
myLog = 'debug';
myLog = 'warning';
myLog = 'error';
Enter fullscreen mode Exit fullscreen mode

MyLog_2 can only be the KEYS

let myLog_2: LOG_LEVEL_KEYS;
myLog_2 = 'DEBUG';
myLog_2 = 'ERROR';
myLog_2 = 'WARNING';
Enter fullscreen mode Exit fullscreen mode

The previous can also be compressed and written like this:

type LOG_LEVEL_VALUES_4 = typeof LOG_LEVEL[keyof typeof LOG_LEVEL];
// Hardcoded will be like this:
type LOG_LEVEL_VALUES_5 = "debug" | "warning" | "error"
Enter fullscreen mode Exit fullscreen mode

Now explaining the TypeScript will be:

type ObjectValues<T> = T[keyof T];

// Imagine it as a function that returns the values of wherever T is.
function ObjectValues(T:any) {
    return T[Object.keys(T)[0]]
}
Enter fullscreen mode Exit fullscreen mode

for example:

type MyType = {
   myString: 'my string',
   myNumber: 23,
}

let myValue:ObjectValues<MyType>;
myValue = 'my string' // can only be the litteral string,
myValue = 23;         // or the litteral value
Enter fullscreen mode Exit fullscreen mode

Explaining the last part

type LogLevel = ObjectValues<typeof LOG_LEVEL>
// Now imagine this part like we actually execute the function and 
// we passed the types provided by "typeof"
let logLevel = ObjectValues({ myString: 'my string'})
Enter fullscreen mode Exit fullscreen mode

Playground Link

. . . . . . . . . . .