Bird
Raised Fist0
Typescriptprogramming~20 mins

Exhaustive pattern matching in Typescript - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
πŸŽ–οΈ
Exhaustive Matcher Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
Output of exhaustive match with union types
What is the output of this TypeScript code using exhaustive pattern matching with match?
Typescript
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; size: number };

function area(shape: Shape): number {
  return match (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.size ** 2;
  }
}

console.log(area({ kind: 'circle', radius: 3 }).toFixed(2));
A"28.27"
B"9"
CTypeScript compile error due to missing case
D"18.85"
Attempts:
2 left
πŸ’‘ Hint
Think about the formula for the area of a circle and how the code calculates it.
❓ Predict Output
intermediate
2:00remaining
Result of exhaustive match with never type
What will this TypeScript code output when run?
Typescript
type Status = 'success' | 'error';

function handleStatus(status: Status) {
  return match (status) {
    case 'success':
      return 'Yay!';
    case 'error':
      return 'Oops!';
  }
}

console.log(handleStatus('error'));
A"Yay!"
BTypeScript compile error: Non-exhaustive match
CRuntime error: Unhandled case
D"Oops!"
Attempts:
2 left
πŸ’‘ Hint
Check which case matches the input 'error'.
πŸ”§ Debug
advanced
2:30remaining
Identify the error in exhaustive match
What error does this TypeScript code produce?
Typescript
type Command = { type: 'start' } | { type: 'stop' } | { type: 'pause' };

function execute(cmd: Command) {
  return match (cmd.type) {
    case 'start':
      return 'Started';
    case 'stop':
      return 'Stopped';
  }
}

execute({ type: 'pause' });
AReturns undefined for 'pause' case
BTypeScript compile error: Non-exhaustive match, missing 'pause' case
CRuntime error: Unhandled case 'pause'
DNo error, returns 'Stopped'
Attempts:
2 left
πŸ’‘ Hint
Check if all union cases are handled in the match.
πŸ“ Syntax
advanced
2:00remaining
Which option causes a syntax error in exhaustive match?
Which of the following TypeScript code snippets causes a syntax error due to incorrect exhaustive pattern matching syntax?
Areturn match (value) { case 'a': 1 case 'b': 2 }
Breturn match (value) { case 'a': return 1; case 'b': return 2; }
Creturn match (value) { case 'a': 1; case 'b': 2; default: 0; }
Dreturn match (value) { case 'a': 1; case 'b': 2; }
Attempts:
2 left
πŸ’‘ Hint
Look for missing punctuation or keywords in the match cases.
πŸš€ Application
expert
2:00remaining
Number of cases needed for exhaustive match
Given this TypeScript union type, how many cases must a match statement cover to be exhaustive?
Typescript
type Event =
  | { type: 'click'; x: number; y: number }
  | { type: 'keydown'; key: string }
  | { type: 'resize'; width: number; height: number }
  | { type: 'scroll'; scrollTop: number };

// How many cases are needed in match(event.type) to be exhaustive?
A3
B5
C4
DDepends on runtime values
Attempts:
2 left
πŸ’‘ Hint
Count the distinct union members by their 'type' property.

Practice

(1/5)
1.

What is the main purpose of exhaustive pattern matching in TypeScript?

easy
A. To allow dynamic typing in TypeScript
B. To ensure all possible cases of a union type are handled
C. To improve runtime performance by skipping cases
D. To automatically generate switch cases

Solution

  1. Step 1: Understand union types and pattern matching

    Exhaustive pattern matching ensures every variant of a union type is explicitly handled in code.
  2. Step 2: Identify the purpose of exhaustive checks

    This prevents missing cases that could cause bugs or unexpected behavior.
  3. Final Answer:

    To ensure all possible cases of a union type are handled -> Option B
  4. Quick Check:

    Exhaustive pattern matching = handle all cases [OK]
Hint: Exhaustive means covering every case without missing any [OK]
Common Mistakes:
  • Thinking it improves runtime speed
  • Confusing with dynamic typing
  • Assuming it auto-generates code
2.

Which of the following switch statements correctly uses exhaustive pattern matching for this union type?

type Shape = 'circle' | 'square' | 'triangle';
easy
A. switch(shape) { case 'circle': break; case 'square': break; case 'triangle': break; }
B. switch(shape) { case 'circle': break; case 'square': break; default: break; }
C. switch(shape) { case 'circle': break; case 'square': break; case 'triangle': break; default: const _exhaustiveCheck: never = shape; }
D. switch(shape) { case 'circle': break; case 'square': break; case 'triangle': break; default: console.log('unknown'); }

Solution

  1. Step 1: Check all cases are handled

    Cases for 'circle', 'square', and 'triangle' are present in options B, C, and D.
  2. Step 2: Verify exhaustive check with never type

    Only switch(shape) { case 'circle': break; case 'square': break; case 'triangle': break; default: const _exhaustiveCheck: never = shape; } uses default with const _exhaustiveCheck: never = shape; to enforce exhaustiveness.
  3. Final Answer:

    switch with all cases and default assigning to never -> Option C
  4. Quick Check:

    Exhaustive switch = all cases + never default [OK]
Hint: Look for default assigning to never for exhaustiveness [OK]
Common Mistakes:
  • Omitting the default case with never assignment
  • Using default without never type
  • Missing one of the union cases
3.

What will be the output of this TypeScript code?

type Status = 'success' | 'error';
function handleStatus(status: Status) {
  switch (status) {
    case 'success':
      return 'Yay!';
    case 'error':
      return 'Oops!';
    default:
      const _exhaustiveCheck: never = status;
      return _exhaustiveCheck;
  }
}
console.log(handleStatus('success'));
medium
A. Compilation error
B. "Oops!"
C. Runtime error
D. "Yay!"

Solution

  1. Step 1: Analyze the switch cases for 'success'

    The input is 'success', so the first case matches and returns 'Yay!'.
  2. Step 2: Check the default case usage

    The default case is unreachable here but ensures exhaustiveness by assigning to never.
  3. Final Answer:

    "Yay!" -> Option D
  4. Quick Check:

    Input 'success' returns 'Yay!' [OK]
Hint: Match input case to return value directly [OK]
Common Mistakes:
  • Thinking default case runs for valid inputs
  • Expecting runtime or compile errors
  • Confusing return values for cases
4.

Identify the error in this exhaustive pattern matching code:

type Direction = 'up' | 'down' | 'left' | 'right';
function move(dir: Direction) {
  switch (dir) {
    case 'up':
      return 'Moving up';
    case 'down':
      return 'Moving down';
    case 'left':
      return 'Moving left';
    default:
      const _exhaustiveCheck: never = dir;
      return _exhaustiveCheck;
  }
}
medium
A. Missing case for 'right' in the switch statement
B. Default case should not assign to never
C. Function should return void instead of string
D. Switch statement syntax is incorrect

Solution

  1. Step 1: Check all union cases in switch

    Cases for 'up', 'down', and 'left' exist, but 'right' is missing.
  2. Step 2: Understand the role of default with never

    The default assigns to never to catch unhandled cases, so missing 'right' causes a compile error.
  3. Final Answer:

    Missing case for 'right' in the switch statement -> Option A
  4. Quick Check:

    All union cases must be handled explicitly [OK]
Hint: Check if all union members have cases before default [OK]
Common Mistakes:
  • Assuming default covers missing cases silently
  • Misusing never assignment in default
  • Ignoring missing union members
5.

Given this nested union type, which switch structure correctly uses exhaustive pattern matching to handle all cases?

type Animal = { type: 'dog'; breed: 'bulldog' | 'beagle' } | { type: 'cat'; color: 'black' | 'white' };
hard
A. switch(animal.type) { case 'dog': switch(animal.breed) { case 'bulldog': break; case 'beagle': break; default: const _exhaustiveCheck: never = animal.breed; } break; case 'cat': switch(animal.color) { case 'black': break; case 'white': break; default: const _exhaustiveCheck: never = animal.color; } break; default: const _exhaustiveCheck: never = animal.type; }
B. switch(animal.type) { case 'dog': if(animal.breed === 'bulldog' || animal.breed === 'beagle') break; break; case 'cat': if(animal.color === 'black' || animal.color === 'white') break; break; default: const _exhaustiveCheck: never = animal.type; }
C. switch(animal.type) { case 'dog': case 'cat': break; default: const _exhaustiveCheck: never = animal.type; }
D. switch(animal.type) { case 'dog': switch(animal.breed) { case 'bulldog': break; default: const _exhaustiveCheck: never = animal.breed; } break; case 'cat': switch(animal.color) { case 'black': break; case 'white': break; } break; default: const _exhaustiveCheck: never = animal.type; }

Solution

  1. Step 1: Check outer switch covers all 'type' cases

    Cases for 'dog' and 'cat' are present with default assigning to never.
  2. Step 2: Check inner switches cover all nested union cases

    For 'dog', both 'bulldog' and 'beagle' are handled with default never; for 'cat', both 'black' and 'white' are handled similarly.
  3. Step 3: Verify no missing cases in nested switches

    All nested union members are covered with exhaustive checks.
  4. Final Answer:

    Nested switches with all cases and never defaults for both levels -> Option A
  5. Quick Check:

    Nested exhaustive switches = all cases + never defaults [OK]
Hint: Use nested switches with never defaults for each union level [OK]
Common Mistakes:
  • Skipping some nested union cases
  • Using if conditions without exhaustive checks
  • Missing never assignment in inner switches
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard