Skip to content

27 — Type operators

One line: Types can be computed from values and from other types, so one definition can produce the rest instead of being copied by hand and drifting.

This chapter covers the operators that make types out of other types. It starts with keyof and typeof, which read keys and a value's type, and indexed access, which looks a property's type up. The utility types come next, as the everyday face of what follows: mapped types walk keys, conditional types with infer ask questions, and template literal types build strings. It ends with recursive types, a type that refers to itself, using a JSON value as the example.

The pages

Page Level In one line Status
keyof and typeof in types 201 In a type, typeof config reads a value's type and keyof lists its keys, so keyof typeof config is "host" | "port". But keyof of a string index signature is string | number, because JavaScript turns number keys into strings. stub
Indexed access types 201 Person["age"] looks a property's type up by name and T[number] asks for any element's type, so (typeof roles)[number] turns an as const array into a union of its strings. The index must be a type: Person[key] with a const key fails. stub
Utility types 201 Pick<User, "nmae"> is an error, but Omit<User, "nmae"> is accepted and removes nothing: Omit takes any string as a key, so a misspelt key passes silently and surfaces later as a missing-property error. stub
Mapped types 301 { [K in keyof T]: T[K] } copies each property's readonly and ? along with its type, while the same loop over a plain union of key names copies neither; -readonly and -? strip them. stub
Conditional types 301 A conditional type on a bare type parameter runs once per union member: ToArray<string | number> is string[] | number[], not (string | number)[], and ToArray<never> is never. Wrapping both sides in [ ] turns the distribution off. stub
Template literal types 301 A template literal type multiplies its unions — `${Size}-${Tone}` with 2 and 3 members is 6 strings — and `${number}px` accepts any non-empty text that Number() reads as a finite number, so "1e3px", "0x1Fpx" and " 12px" all pass. stub
Recursive types 301 type Json = … | Json[] | { [key: string]: Json } names itself and covers JSON at any depth, yet a value typed by an interface with the same fields is rejected, because only type aliases get an implicit index signature. stub

Boundaries

Generic functions and constraints are in Generics; the run-time typeof operator is in Values and types.