Chapter 40: TypeScript Exercises
TypeScript Exercises guide.
I prepared it as if we are in a small group workshop right now (Feb 2026). We go from beginner → intermediate → advanced → real-world-ish patterns.
Each section has:
- short goal explanation
- the exercise itself
- difficulty rating
- hints (if you get stuck)
- example solution (scroll down only after trying!)
You can solve them directly in https://www.typescriptlang.org/play (recommended) or in your own project.
Level 1 – Warm-up (very beginner friendly)
Exercise 1.1 – Basic annotations & inference Difficulty: ★☆☆☆☆
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// Fix / improve every line that needs attention. // Do NOT use 'any' anywhere. let count; count = 42; count = "forty-two"; const user = { id: 1, name: "Sara", isActive: true, scores: [92, 85, 78] }; function greet(name, age) { return `Hello ${name}, you are ${age} years old`; } console.log(greet("Rahul", 28)); console.log(greet(28, "Rahul")); // should be error |
Exercise 1.2 – Literal types + union Difficulty: ★★☆☆☆
Create type Size that only allows these exact string values: “xs” | “sm” | “md” | “lg” | “xl” | “2xl”
Then create function getPadding(size: Size) that returns different padding values:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
xs → "0.25rem" sm → "0.5rem" md → "1rem" lg → "1.5rem" xl → "2rem" 2xl → "3rem" |
Bonus: make sure TypeScript autocompletes the possible values when you write getPadding(“…
Level 2 – Functions, objects, arrays
Exercise 2.1 – Function overloads or generics Difficulty: ★★☆☆☆
Write function firstElement that:
- accepts array of anything
- returns first element or undefined if array is empty
- preserves the exact element type
|
0 1 2 3 4 5 6 7 8 9 |
firstElement([1,2,3]) // → number | undefined firstElement(["a","b"]) // → string | undefined firstElement([]) // → undefined firstElement([{id:1}]) // → {id:number} | undefined |
Exercise 2.2 – Deep partial type Difficulty: ★★★☆☆
Create type DeepPartial<T> so that this works:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
interface User { id: number; name: string; address: { street: string; city: string; geo: { lat: number; lng: number; } }; tags: string[]; } const partial: DeepPartial<User> = { name: "Sara", address: { geo: { lat: 17.3850 // city can be missing – ok } }, tags: ["dev"] // can be partial too }; |
Level 3 – Real-world patterns
Exercise 3.1 – Discriminated union + exhaustive check Difficulty: ★★★☆☆
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
type ApiState = | { status: "idle" } | { status: "loading" } | { status: "success"; data: string[] } | { status: "error"; message: string }; function renderState(state: ApiState): JSX.Element { // Use switch + default case that forces you to handle every variant // (should give compile error if you forget one case) } |
Exercise 3.2 – Branded / nominal types for IDs Difficulty: ★★★★☆
Create two branded types so that these lines give error:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
type UserId = string & { __brand: "UserId" }; type PostId = string & { __brand: "PostId" }; function getUserPosts(userId: UserId): Post[] { // ... } const uid = "user_abc123" as UserId; const pid = "post_456" as PostId; getUserPosts(uid); // ok getUserPosts(pid); // ← should be compile error! |
Exercise 3.3 – infer + conditional types Difficulty: ★★★★☆
Create type UnwrapPromise<T> that recursively unwraps nested promises:
|
0 1 2 3 4 5 6 7 8 9 |
type A = UnwrapPromise<Promise<string>>; // string type B = UnwrapPromise<Promise<Promise<number>>>; // number type C = UnwrapPromise<Promise<Promise<Promise<boolean>>>>; // boolean type D = UnwrapPromise<string>; // string |
Level 4 – React + modern ecosystem patterns
Exercise 4.1 – Typed custom hook
Create useLocalStorage hook with full type safety:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
function useLocalStorage<T>(key: string, initialValue: T) { // return [value: T, setValue: (v: T | ((prev: T) => T)) => void] // preserve literal types when possible } // Usage should be nice: const [theme, setTheme] = useLocalStorage<"light" | "dark">("theme", "light"); |
Exercise 4.2 – Generic table component props
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
interface Column<T> { key: keyof T; header: string; render?: (value: T[keyof T], row: T) => ReactNode; } interface TableProps<T> { data: T[]; columns: Column<T>[]; } function GenericTable<T>(props: TableProps<T>) { // ... } // Should give good autocompletion & type errors const users = [{ id: 1, name: "Sara", age: 28 }]; <GenericTable data={users} columns={[ { key: "name", header: "Name" }, { key: "age", header: "Age", render: (age) => `${age} years` }, // { key: "email" } → should error – no email field ]} /> |
Bonus – Pick one harder challenge
Challenge A – Path type extractor Create type Paths<T> that produces union of all possible deep key paths:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
type User = { id: number; profile: { name: string; address: { city: string; zip: number }; }; roles: string[]; }; type UserPaths = Paths<User>; // "id" // "profile" // "profile.name" // "profile.address" // "profile.address.city" // "profile.address.zip" // "roles" |
Challenge B – Type-safe route builder Create function route that builds URL with parameters safely:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
const routes = { userProfile: "/users/:id", postDetail: "/posts/:postId/comments/:commentId" } as const; const url = route("userProfile", { id: "123" }); // "/users/123" const url2 = route("postDetail", { postId: "abc", commentId: "999" }); // compile error if missing param or wrong key |
How to practice effectively
- Do 2–4 exercises per day (not more)
- Always try first without looking at hints/solution
- After you finish → compare with my solution → ask yourself: „Which version is easier to read / refactor / extend?“
- Put your solutions into a GitHub repo called ts-exercises
- After ~30 exercises → start using these patterns in your real project
Which level / exercise would you like to start with right now? Or do you want me to pick 5 exercises that match your current skill best?
Just tell me your preference 😄
