Course outline · 0% complete

0/26 lessons0%

Course overview →

keyof and Record

lesson 7-2 · ~11 min · 22/26

keyof: the property names as a type

keyof T is a union of T's property names as literal types:

interface Point {
  x: number;
  y: number;
}
// keyof Point  is  "x" | "y"

function getCoord(p: Point, key: keyof Point): number {
  return p[key];
}

getCoord(p, "x") compiles, getCoord(p, "z") does not. In plain JavaScript, p[key] with a misspelled key silently returns undefined. With keyof, property access by name is checked like everything else. You already saw Pick<User, "id" | "name"> in the last lesson, that K is constrained with keyof behind the scenes.

Code exercise · typescript

Run it, then call getCoord({ x: 3, y: 7 }, "z") and read the error listing the allowed keys.

Record: a typed lookup table

Record<K, V> builds an object type with keys K and values V. Pair it with a union of literals for an exhaustive table:

type Fruit = "apple" | "banana" | "cherry";

const stock: Record<Fruit, number> = {
  apple: 4,
  banana: 0,
  cherry: 12,
};

Two guarantees at once: every fruit must appear (forget cherry and it will not compile), and no stray keys sneak in. Compare the JavaScript habit of plain object maps where a typo creates a new key instead of an error. Record<string, number> is also legal when the key set is open-ended.

Code exercise · typescript

Record<string, number> with open-ended keys, used as a tally. Note the honest wrinkle: the type says counts[w] is a number, but a key seen for the first time is undefined at runtime, so ?? 0 (lesson 4-4) supplies the starting value. Run it, then print counts["fox"] to see what a never-seen key gives.

Code exercise · typescript

Your turn. Define type Day = "mon" | "tue" | "wed". Create steps: Record<Day, number> with mon 4200, tue 8000, wed 5600. Add the three values into total and print "total steps: " + total.

Quiz

You declare const scores: Record<"alice" | "bob", number> = { alice: 3 }. What happens?