keyof, typeof, and infer

⭐ Interview Importance: HIGH
⏱️ Revision Time: 4 min

TL;DR

These three operators are the foundation of advanced TypeScript programming:

  • typeof: Extracts the type from a JavaScript variable.
  • keyof: Extracts a union of keys from a TypeScript object type.
  • infer: Extracts a type from inside another type (used in conditional types).

1. The typeof Operator

In standard JavaScript, typeof x returns a string like "number".
In the Type Context of TypeScript, typeof takes a JavaScript variable and generates a TypeScript Type based on its shape.

const defaultConfig = { port: 8080, secure: true };

// We don't want to manually write an interface. Let TS do it!
type Config = typeof defaultConfig; 
// Type Config is: { port: number, secure: boolean }

2. The keyof Operator

It takes an object type (not a variable) and produces a string or numeric literal union of its keys.

interface User {
    id: number;
    name: string;
}

type UserKeys = keyof User; 
// Type UserKeys is exactly: "id" | "name"

// Great for safe property access functions!
function getProperty<T, K extends keyof T>(obj: T, key: K) {
    return obj[key];
}

3. The infer Keyword

infer can only be used inside the condition of a Conditional Type (T extends ...). It tells TypeScript: “I don’t know what this inner type is, but figure it out, save it to a temporary variable, and let me use it.”

// "If T is an Array of some type Item, return Item. Otherwise, return T."
type UnpackArray<T> = T extends Array<infer Item> ? Item : T;

type A = UnpackArray<string[]>; // Evaluates to 'string'
type B = UnpackArray<number>;   // Evaluates to 'number'

Common Interview Questions

Can you combine keyof and typeof?

Yes! It is extremely common when you have a static JavaScript object (like an enum replacement) and you want a type representing all its keys.

const Colors = { Red: "#f00", Blue: "#00f" };
type ColorNames = keyof typeof Colors; // "Red" | "Blue"

How do you extract the Return Type of a function using infer?

This is how the built-in ReturnType<T> utility works:

type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

It asks: “Does T look like a function? If yes, infer whatever it returns into R, and give me R.”