Mapped and conditional types
In TypeScript you can build a new type out of an old one. Follow one seven-line file as keyof lists User's keys, a mapped type loops over them, T[K] looks up each key's type, and a conditional type turns numbers into strings. tsc computes Form = { id: string; name: string; admin: boolean }, then uses it to catch a wrong value.
5 quick questions
Pick an answer to see why. Your score saves with your progress.
01type User = { id: number; name: string; admin: boolean }. What is keyof User?
keyof gives the key names, not their types, as a union of string literal types. The types of the properties would be User[keyof User], which is number | string | boolean.
02What does a mapped type such as { [K in keyof T]: T[K] } do?
[K in keyof T] goes over every key K of T at compile time and adds one property per key. With T[K] as the property type, the result is a copy of T.
03With T = User, what is T["id"]?
T[K] is an indexed access type: it looks up the type of a property. User's id property has type number.
04In the lesson's AsText, what type does admin get? (T[K] extends number ? string : T[K])
boolean is not assignable to number, so the test says no and the second branch keeps T[K], which is boolean.
05Form is { id: string; name: string; admin: boolean }. Why does const f: Form = { id: 42, name: "Ada", admin: false } fail?
tsc reports error TS2322: Type 'number' is not assignable to type 'string'. A computed type checks values exactly like a hand-written one.
Glossary
- keyof
- A type operator that gives the key names of an object type as a union, such as "id" | "name".
- Union type
- A type made of several options joined with |; a value of the type can be any one of them.
- Literal type
- A type with exactly one value, such as "id" (only that exact text) or 42.
- Indexed access type
- T[K]: the type of property K inside type T, such as User["id"], which is number.
- Mapped type
- A type like { [K in keyof T]: ... } that makes one property for each key of another type.
- Conditional type
- A extends B ? X : Y: the type X if A is assignable to B, otherwise the type Y.
- Assignable
- Type A is assignable to type B when every value of A is also allowed as a B.
- Generic type
- A type with a parameter, such as AsText<T>; you fill it in with a real type, as in AsText<User>.
Notes and sources
- The built-in utility type Partial<T> is a mapped type too: TypeScript defines it as type Partial<T> = { [P in keyof T]?: T[P] }; The ? after the key makes every property optional; readonly in front of [P in keyof T] makes every property read-only.
- When the type being tested is a bare type parameter, such as T in T extends string ? ..., a conditional type is applied to each member of a union separately ("distributive"). Here the tested type is T[K], not a bare T, so boolean is tested as a whole and stays boolean.
- Hovering over Form in an editor shows the computed object type { id: string; name: string; admin: boolean }. Hovering over the variable f shows AsText<User>, and hovering over its id property shows string. (Checked with the TypeScript 5.9 language service, which gives VS Code its hover text.)
- The seven lines on the card are one real file. With id: 42 tsc 5.9 reports exactly the error shown; with id: "42" it reports none, and the emitted JavaScript runs in Node.js.
- TypeScript Handbook: Keyof Type Operator
- TypeScript Handbook: Indexed Access Types
- TypeScript Handbook: Mapped Types
- TypeScript Handbook: Conditional Types
- TypeScript Handbook: Creating Types from Types
- TypeScript Handbook: Utility Types (Partial)
- TypeScript source: lib.es5.d.ts (definition of Partial<T>)
Quiz Unlocks after the last step.