Patterns
One page per question. Every recipe compiles, every result is the type the compiler printed, and every page says where the recipe goes wrong.
Every recipe and every result is compiled at build time
- How do I stop a `UserId` being passed where an `OrderId` was expected, when both are just strings?TypeScript is structural, so two aliases of `string` are the same type. A phantom property makes them different without changing the value.Brand a primitive
- How do I get a compile error when someone adds a case to a union and forgets to handle it?Narrow every case and assign what is left to `never`. Once the union grows, what is left is no longer nothing, and the assignment fails.Make a switch exhaustive
- How do I stop `Omit<User, "nmae">` silently succeeding and removing nothing?The built-in constrains its key parameter to `keyof any`, which is every key there could ever be. Constrain it to `keyof T` instead.Make Omit catch typos
- How do I turn `{ a: string } & { b: number }` into `{ a: string; b: number }` so tooltips are readable and equality checks pass?A homomorphic mapped type walks every key once and rebuilds a single object. Modifiers survive; the intersection does not.Flatten an intersection
- Why does `Object.keys(config)` give me `string[]` instead of the keys I can see right there?Because a value can have more keys than its type declares, and `Object.keys` returns all of them. Narrowing the return is a deliberate, local decision — not a fix for a bug.Get typed keys from an object
- How do I accept an options object where every field is optional, but the empty object is not allowed?Build one variant per key where that key is required and the rest are optional, then union them. Any single supplied key satisfies at least one variant.Require at least one property