Discriminated unions
This is the most common way to debug “type safety” in professional TypeScript codebases (especially with Redux or API responses).
The scenario
You have a function that processes different types of API responses. The logic is currently “leaking” because it's trying to access properties that don't exist on all possible response types.
The buggy code
1interface Success {
2 status: 'success';
3 data: string;
4}
5
6interface Failure {
7 status: 'error';
8 errorMessage: string;
9}
10
11type ApiResponse = Success | Failure;
12
13function handleResponse(response: ApiResponse) {
14 // BUG: The compiler complains here.
15 // "Property 'data' does not exist on type 'ApiResponse'."
16 console.log("Result: " + response.data);
17
18 if (response.status === 'error') {
19 console.log("Error: " + response.errorMessage);
20 }
21}Why this is a great debugging example
The interviewer wants to see you use the status field (the “discriminant”) to narrow the type.
The fix
1function handleResponse(response: ApiResponse) {
2 if (response.status === 'success') {
3 // Because of the 'if', TS now knows response is strictly the 'Success' interface
4 console.log("Result: " + response.data);
5 } else {
6 // TS now knows response must be the 'Failure' interface
7 console.log("Error: " + response.errorMessage);
8 }
9}