The keyof Operator

Keys as a Union

keyof T produces a union of the property names of T. If T has id, name and price, keyof T is "id" | "name" | "price".

Example

type Product = { id: number; name: string; price: number };
type ProductKey = keyof Product; // "id" | "name" | "price"

function sortBy(items: Product[], key: ProductKey): Product[] {
  return [...items].sort((a, b) => (a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0));
}

const items: Product[] = [
  { id: 3, name: "Toaster", price: 1899 },
  { id: 1, name: "Kettle", price: 1299 },
  { id: 2, name: "Blender", price: 2499 },
];

console.log(sortBy(items, "price").map((p) => p.name));
console.log(sortBy(items, "name").map((p) => p.name));

Output

[ 'Kettle', 'Toaster', 'Blender' ]
[ 'Blender', 'Kettle', 'Toaster' ]

Invalid Key

Example

"rating" is not a key of Product (TS2345). A column rename in the type immediately breaks every outdated sort call.

type Product = { id: number; name: string; price: number };
function sortBy(items: Product[], key: keyof Product): Product[] {
  return items;
}
sortBy([], "rating");

Compiler output (tsc)

Line 5: error TS2345: Argument of type '"rating"' is not assignable to parameter of type 'keyof Product'.