Bird
Raised Fist0
Typescriptprogramming~20 mins

Exhaustive checking with never in Typescript - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Never Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this exhaustive check with never?
Consider this TypeScript code that uses exhaustive checking with never. What will be logged when handleShape is called with a Circle?
Typescript
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; size: number };

function handleShape(shape: Shape) {
  switch (shape.kind) {
    case 'circle':
      console.log(`Circle with radius ${shape.radius}`);
      break;
    case 'square':
      console.log(`Square with size ${shape.size}`);
      break;
    default:
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}

handleShape({ kind: 'circle', radius: 5 });
ASquare with size 5
BTypeScript compile error due to unreachable default
CCircle with radius 5
DRuntime error because of never assignment
Attempts:
2 left
💡 Hint
Think about what the default case does and when it runs.
❓ Predict Output
intermediate
2:00remaining
What error does this exhaustive check produce?
Given this TypeScript code, what error will the compiler produce?
Typescript
type Animal = { type: 'dog'; bark: () => void } | { type: 'cat'; meow: () => void };

function speak(animal: Animal) {
  switch (animal.type) {
    case 'dog':
      animal.bark();
      break;
    // Missing case for 'cat'
    default:
      const _exhaustiveCheck: never = animal;
      return _exhaustiveCheck;
  }
}
AType 'Animal' is not assignable to type 'never' error at _exhaustiveCheck
BNo error, code compiles fine
CRuntime error when calling speak with a cat
DSyntax error due to missing case
Attempts:
2 left
💡 Hint
Check what happens when a union member is not handled in the switch.
🔧 Debug
advanced
2:30remaining
Why does this exhaustive check fail to catch a missing case?
Examine this TypeScript code. Why does the exhaustive check with never not produce a compile error even though a case is missing?
Typescript
type Fruit = { kind: 'apple'; color: string } | { kind: 'banana'; length: number } | { kind: 'orange'; diameter: number };

function describeFruit(fruit: Fruit) {
  switch (fruit.kind) {
    case 'apple':
      console.log(`Apple color: ${fruit.color}`);
      break;
    case 'banana':
      console.log(`Banana length: ${fruit.length}`);
      break;
    // Missing 'orange' case
    default:
      const _exhaustiveCheck: never = fruit;
      return _exhaustiveCheck;
  }
}

// Why no compile error?
ABecause the Fruit type is not a discriminated union with a literal 'kind' property
BBecause the default case is unreachable and TypeScript skips the check
CBecause Fruit is not a union type
DBecause the Fruit type is declared with a type alias instead of interface
Attempts:
2 left
💡 Hint
Check the type of the discriminant property and if it is a literal type.
📝 Syntax
advanced
2:00remaining
Which option correctly uses exhaustive checking with never?
Which of the following TypeScript code snippets correctly implements exhaustive checking with never in a switch statement?
A
switch (value) {
  case 'a':
    // do something
    break;
  case 'b':
    // do something else
    break;
  default:
    const check: any = value;
    break;
}
B
switch (value) {
  case 'a':
    // do something
    break;
  default:
    const check: never = value;
    break;
}
C
switch (value) {
  case 'a':
    // do something
  case 'b':
    // do something else
  default:
    const check: never = value;
}
D
switch (value) {
  case 'a':
    // do something
    break;
  case 'b':
    // do something else
    break;
  default:
    const check: never = value;
    break;
}
Attempts:
2 left
💡 Hint
Look for all cases handled and correct use of never in default.
🚀 Application
expert
2:30remaining
How many items are in the resulting array after exhaustive check filtering?
Given this TypeScript code that uses exhaustive checking with never and filters an array of shapes, how many items remain in filteredShapes?
Typescript
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; size: number } | { kind: 'triangle'; base: number; height: number };

const shapes: Shape[] = [
  { kind: 'circle', radius: 10 },
  { kind: 'square', size: 5 },
  { kind: 'triangle', base: 4, height: 3 }
];

function isCircle(shape: Shape): shape is Extract<Shape, { kind: 'circle' }> {
  switch (shape.kind) {
    case 'circle':
      return true;
    case 'square':
    case 'triangle':
      return false;
    default:
      const _exhaustiveCheck: never = shape;
      return _exhaustiveCheck;
  }
}

const filteredShapes = shapes.filter(isCircle);
A2
B1
C3
D0
Attempts:
2 left
💡 Hint
Count how many shapes have kind 'circle'.

Practice

(1/5)
1. What is the main purpose of using never in exhaustive checking in TypeScript?
easy
A. To declare a variable that can hold any value
B. To allow any type of value without restrictions
C. To ignore errors during compilation
D. To ensure all possible cases are handled in a switch or conditional

Solution

  1. Step 1: Understand the role of never in exhaustive checks

    never is used to represent values that should never occur, helping catch unhandled cases.
  2. Step 2: Connect never usage to exhaustive case handling

    By forcing a function to accept never, TypeScript ensures all cases are covered, or else a compile error occurs.
  3. Final Answer:

    To ensure all possible cases are handled in a switch or conditional -> Option D
  4. Quick Check:

    Exhaustive checking = catch all cases [OK]
Hint: Use never to catch missing cases in switch statements [OK]
Common Mistakes:
  • Thinking never allows any value
  • Using never to ignore errors
  • Confusing never with unknown type
2. Which of the following is the correct syntax for a helper function that uses never to enforce exhaustive checking?
easy
A. function assertNever(x: never): never { throw new Error('Unexpected value: ' + x); }
B. function assertNever(x: any): void { console.log(x); }
C. function assertNever(x: unknown): never { return x; }
D. function assertNever(x: never): void { return; }

Solution

  1. Step 1: Identify correct parameter and return types

    The helper function must accept a parameter of type never and return never because it throws an error.
  2. Step 2: Check function body matches expected behavior

    The function throws an error with the unexpected value, which is the standard pattern for exhaustive checks.
  3. Final Answer:

    function assertNever(x: never): never { throw new Error('Unexpected value: ' + x); } -> Option A
  4. Quick Check:

    Helper function with never param and throw = correct [OK]
Hint: Helper must take never and throw error to enforce checks [OK]
Common Mistakes:
  • Using any or unknown instead of never
  • Not throwing an error inside the function
  • Returning void instead of never
3. What will be the output of this TypeScript code?
type Shape = 'circle' | 'square';
function area(shape: Shape) {
  switch (shape) {
    case 'circle':
      return 3.14 * 2 * 2;
    // Missing case for 'square'
    default:
      return assertNever(shape);
  }
}

function assertNever(x: never): never {
  throw new Error('Unexpected shape: ' + x);
}

console.log(area('square'));
medium
A. Returns 12.56
B. Throws Error: Unexpected shape: square
C. Returns undefined
D. Compilation error due to missing case

Solution

  1. Step 1: Analyze switch cases and input

    The function handles 'circle' but not 'square', so at runtime, calling area('square') hits the default case.
  2. Step 2: Understand assertNever behavior at runtime

    The assertNever function throws an error with the unexpected shape, so the program throws a runtime error.
  3. Final Answer:

    Throws Error: Unexpected shape: square -> Option B
  4. Quick Check:

    Missing case causes runtime error when called [OK]
Hint: Missing case triggers runtime error when called [OK]
Common Mistakes:
  • Assuming missing case returns undefined
  • Thinking it returns a number for all inputs
  • Expecting compile error instead of runtime error
4. Identify the error in this TypeScript code using exhaustive checking:
type Direction = 'up' | 'down' | 'left';
function move(dir: Direction) {
  switch (dir) {
    case 'up':
      return 'Moving up';
    case 'down':
      return 'Moving down';
    default:
      return assertNever(dir);
  }
}

function assertNever(x: never): never {
  throw new Error('Unexpected direction: ' + x);
}
medium
A. Missing case for 'left' in switch statement
B. assertNever function has wrong parameter type
C. Switch statement should not have a default case
D. Function move should return void instead of string

Solution

  1. Step 1: Check all union cases in switch

    The type Direction has 'up', 'down', and 'left', but 'left' is missing in the switch.
  2. Step 2: Understand impact of missing case with assertNever

    Missing 'left' causes default to call assertNever with a string, which is not never, causing a compile error.
  3. Final Answer:

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

    All union cases must be handled [OK]
Hint: Check all union cases explicitly to avoid errors [OK]
Common Mistakes:
  • Ignoring missing union cases
  • Thinking default case covers all safely
  • Wrong assertNever parameter type
5. Given this code, how can you modify it to ensure exhaustive checking for all Status values?
type Status = 'success' | 'error' | 'loading';

function handleStatus(status: Status) {
  switch (status) {
    case 'success':
      return 'Done';
    case 'error':
      return 'Failed';
    // Missing 'loading' case
    default:
      return assertNever(status);
  }
}

function assertNever(x: never): never {
  throw new Error('Unexpected status: ' + x);
}
hard
A. Change the type Status to include only 'success' and 'error'
B. Remove the default case and rely on TypeScript errors
C. Add a case for 'loading' in the switch statement
D. Change assertNever parameter type to any

Solution

  1. Step 1: Identify missing union case in switch

    The 'loading' case is missing, so the switch is not exhaustive.
  2. Step 2: Add missing case to ensure all Status values are handled

    Adding case 'loading': with appropriate return ensures exhaustive checking and no runtime errors.
  3. Final Answer:

    Add a case for 'loading' in the switch statement -> Option C
  4. Quick Check:

    All union members must have cases [OK]
Hint: Add missing union cases to switch for full coverage [OK]
Common Mistakes:
  • Removing default case without adding missing cases
  • Changing type to avoid handling all cases
  • Using any instead of never in assertNever
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