How do you handle an API returning 200 for success and failure?
This tests TypeScript narrowing and runtime validation of ambiguous 200 responses. A strong answer uses a discriminated union, narrows with a type guard, and validates shape before branching. Red flag: casting the body with as and skipping runtime checks.
WHAT THIS TESTS: This question evaluates whether you can enforce type safety across a network boundary where the HTTP status code is unreliable. The interviewer cares about three specific skills: designing a discriminated union in TypeScript, applying narrowing via type guards, and insisting on runtime validation because fetch responses are unknown at runtime.
A GOOD ANSWER COVERS: First, model the API payload as a discriminated union using a literal type discriminator such as status with values success or error. Second, treat the JSON body as unknown after the fetch, not any, so the compiler forces you to validate it before use. Third, use a type guard or a narrowing check like if body.status equals success to refine the union to the specific success or error branch inside the control flow. Fourth, wrap the operation in a helper that returns a Result type or a standardized object such as ok true with data or ok false with error so that downstream code must handle both paths explicitly.
COMMON WRONG ANSWERS: Casting the response directly to a named success type using the as keyword is the biggest red flag because it bypasses both runtime safety and the type checker. Another weak pattern is checking whether the string data is a key in the body to distinguish shapes; this breaks if the API adds extra fields or changes naming. Simply returning the parsed JSON without branching and letting the consumer check body.status is also poor because it leaks the wire format everywhere and offers no compile-time guarantees.
LIKELY FOLLOW-UPS: The interviewer may ask how you would handle an unexpected third status value; a strong response mentions exhaustiveness checking with a never assignment in the default case. They may also ask about async error propagation, in which case you should discuss whether to throw custom error classes for failures or return Result objects to keep exceptions reserved for truly exceptional transport errors. A third follow-up could be the trade-off between manual type guards and schema validation libraries like Zod.
ONE CONCRETE EXAMPLE: Write a fetch wrapper where you assign the parsed JSON to a variable typed as unknown. Then define a type ApiResponse as a union of two objects: one with status success and a data property, and one with status error and a message property. Pass the parsed value into a helper function isSuccess that first checks the value is a record object, then checks that typeof status is string and that status equals success, and verifies that data exists. Inside the wrapper, if isSuccess returns true, return an object with ok true and the data; otherwise return ok false and the error message. The caller then checks result.ok in a type-safe way.
Read the original → typescriptlang.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.