Types from types
Start with one type. User describes an object with three fields: id is a number, name and email are strings. No field has a ? after its name, so all three are required.
A utility type is a generic type built into TypeScript. You pass it a type in angle brackets, as in Partial<User>, and it gives back a new type. Nothing is copied by hand, so the two never drift apart.
Change every field
Partial<User> sends every field through and marks each one optional with a ?. Out comes { id?: number; name?: string; email?: string }. A value of this type may have any of the fields, or none.
let p: Partial<User> = { id: 7 } passes the check: id is there, name and email are left out. Type the same object as User and tsc refuses with error TS2739: name and email are missing.
Readonly<User> keeps all three fields but marks each one readonly. You can read them, but assigning one, as in locked.name = "Bo", is a compile error: Cannot assign to 'name' because it is a read-only property.
Choose the fields
Pick takes a second argument: the keys to keep, joined with |. Pick<User, "id" | "name"> lets only id and name through, and email stays behind. Out comes { id: number; name: string }.
Omit is the opposite: every field except the keys you name. Omit<User, "id"> leaves id behind, giving { name: string; email: string }: handy for a new user that has no id yet.
How it works
The keys are checked too. User has no age, so Pick<User, "age"> fails with error TS2344: Type '"age"' does not satisfy the constraint 'keyof User'. keyof User means "id" | "name" | "email".
Partial is no magic. TypeScript defines it as a mapped type, { [P in keyof T]?: T[P] }. P visits each key of T in turn, and the ? makes that field optional. Written by hand for User, line 6 gives the same type.
What happens
;; step 1/9 · shape
1 interface User {
> 2 id: number;
> 3 name: string;
> 4 email: string;
5 }
6 // all three fields are required
keyof User = "id" | "name" | "email"
a User value must have all three fields
Partial, Readonly, Pick and Omit are declared in lib.es5.d.ts, the type library tsc loads by default. They exist only while checking: like every type, they are erased and add nothing to the JavaScript. Omit does not check its keys: it is declared as Omit<T, K extends keyof any>, so Omit<User, "age"> is allowed and simply removes nothing. Pick requires K extends keyof T, which is why the typo is caught.