Classic Type Challenges
Expert · 20 min read · ▶ live playground · ✦ checkpoint
Classic TypeScript type challenges teach you to read type-level code by solving small, named puzzles. A type challenge is a tiny exercise where the answer is a type alias, not a runtime function.
The goal is not to become clever. The goal is to recognize the moves behind the libraries you already use: pick fields, read function returns, freeze nested shapes, parse strings, and preserve tuple positions.
Warm-ups: pick, return, readonly
A type-level assertion is a checker-only test that fails when two types stop matching. We will use the same Expect<Equal<...>> shape from 25.1.
Start with three classics. MyPick keeps selected object keys. MyReturnType reads a function's return type. DeepReadonly walks nested object shapes and makes every property readonly.
→ Search launch is on pro
Read each alias like a small function. MyPick takes a shape and key set, then loops over those keys. MyReturnType pattern-matches a function and names the result type with infer. DeepReadonly branches: functions stay callable, objects get mapped, primitives return unchanged.
String parsing: trim, camel, route params
A string parser type is a type that pattern-matches string literal types. You are not parsing runtime strings here. You are transforming known string sets before erasure.
Template literal types make this possible. The trick is always the same: match the front, name the rest, and stop when no pattern matches.
→ mina opened search
TrimLeft is shallow recursion over a string. CamelCase changes one dash at a time. RouteParams returns a union of parameter names, then the mapped type turns that union into an object shape.
Tuple gymnastics: last, zip, chunk
A tuple challenge is a type exercise over fixed array positions. This is where types-as-sets meets the tuple-seat idea from Section 2: each position carries its own type.
Last reads the final position. Zip pairs positions from two tuples. Chunk groups items into small tuple batches. These are useful because real helpers often need to preserve call argument positions.
→ 2 launch chunks
This is the point where challenge solutions can start feeling like a maze. Slow down. Find the inputs, the branch, the recursive call, and the stopping case. If you cannot name those four parts, do not compress the type further.
When you browse that repo, take a guided path:
- Start with warm-ups that mirror built-ins you know.
- Move to string parsing only after template literal types feel readable.
- Move to tuple work only after you can read
infer First, ...infer Rest. - Keep one playground open and make every solution prove itself with
Expect<Equal<...>>.
Next, you will learn when to stop. The same type-level tools that make libraries feel smart can make a team miserable when they hide intent or slow the checker down.
Checkpoint
Answer all three to mark this lesson complete