Mastering TypeScript's Conditional Types for Advanced Error Handling

Learn how to use TypeScript's conditional types to create advanced, type-safe error handling patterns in your applications.

Error handling is a crucial part of any application. In TypeScript, conditional types enable you to create flexible, type-safe error handlers that adapt based on the shape or type of your data. This guide will introduce you to conditional types and show you how to leverage them for advanced error handling, making your code more robust and developer-friendly.

Conditional types in TypeScript let you choose types based on a condition. It’s like an if-else statement but for types. The syntax looks like this: `T extends U ? X : Y` where TypeScript evaluates if type `T` extends (is assignable to) type `U`. If true, it returns type `X`; otherwise, it returns type `Y`.

Let's start with a simple example to understand how conditional types can help us with error handling.

typescript
type ApiResponse<T> = {
  data: T;
  error?: never;
} | {
  data?: never;
  error: string;
};

Here, `ApiResponse` represents a type that either contains `data` or an `error` string, but never both at the same time. Now imagine you have a function that fetches user data or returns an error. We want to create a conditional type that extracts the data type only if there is no error.

typescript
type ExtractData<T> = T extends { error: string } ? never : T extends { data: infer D } ? D : never;

Explanation: - If the type has an `error` key with a string, it returns `never` (indicating no data). - Otherwise, if it has a `data` key, it extracts the type of `data` using `infer D`. - If neither matches, it returns `never`.

Let's see this in practice with a sample function and response.

typescript
function handleResponse<T extends ApiResponse<any>>(response: T): ExtractData<T> | null {
  if ('error' in response) {
    console.error('Error:', response.error);
    return null;
  }
  return response.data as ExtractData<T>;
}

Here, `handleResponse` uses the `ExtractData` conditional type to safely extract data if there is no error. If an error exists, it logs the error and returns `null`. This approach enforces type safety and clearly separates error and success states.

To summarize, conditional types allow you to: - Dynamically select types based on conditions - Create safer, more expressive error handling - Extract useful types from complex union types By mastering them, you can build robust TypeScript apps that handle errors gracefully at compile-time, reducing runtime bugs.

Keep experimenting with conditional types, combine them with utility types like `infer`, and incorporate them into your error handling strategy to elevate your TypeScript code quality!