Deep Dive into TypeScript's Conditional Types for Advanced Error Handling

Learn how to leverage TypeScript's powerful conditional types to create advanced, flexible error handling patterns in your applications.

TypeScript is a powerful language that enhances JavaScript with types, enabling safer coding and better developer experience. One super useful feature for advanced error handling is conditional types. These allow you to create types that change based on conditions, making your error management more precise and adaptable.

In this article, we'll explore how to use conditional types in TypeScript to build flexible error handling patterns. We'll start with simple examples and then get into more practical use cases involving API responses and custom error types.

### What are Conditional Types? Conditional types allow you to relate types to each other based on a condition. They follow a syntax like `T extends U ? X : Y`, meaning: if type `T` is assignable to type `U`, then use type `X`; otherwise use type `Y`.

typescript
type IsString<T> = T extends string ? 'Yes' : 'No';

type Test1 = IsString<string>;  // 'Yes'
type Test2 = IsString<number>;  // 'No'

This flexibility is perfect for error handling because it enables creating utility types that can adapt based on passed types or conditions in your code.

### Creating a Basic Conditional Error Type Suppose you want a function that returns different error object shapes depending on the context. You can use conditional types to define which error type to return.

typescript
type ApiError = { message: string; statusCode: number };
type ValidationError = { message: string; fields: string[] };

type ErrorType<T> = T extends 'api' ? ApiError : ValidationError;

Here, `ErrorType` changes based on the string literal type passed to it.

typescript
function handleError<T extends 'api' | 'validation'>(type: T, errorData: ErrorType<T>): void {
  if (type === 'api') {
    console.log('API error:', errorData.statusCode, errorData.message);
  } else {
    console.log('Validation error on fields:', errorData.fields.join(', '));
  }
}

handleError('api', { message: 'Not Found', statusCode: 404 });
handleError('validation', { message: 'Invalid input', fields: ['email', 'password'] });

Try passing wrong error data for the type, and TypeScript will catch the mistake at compile time.

### Using Conditional Types for API Response Error Handling Often when dealing with API responses, you want to differentiate success from error responses clearly.

typescript
type ApiResponse<T> =
  T extends { error: true }
    ? { error: true; code: number; message: string }
    : { error: false; data: T };

function handleApiResponse<T>(response: ApiResponse<T>) {
  if (response.error) {
    console.error(`Error (${response.code}):`, response.message);
  } else {
    console.log('Success:', response.data);
  }
}

This type will ensure you provide either a successful response with data or an error with proper error details.

### Summary Conditional types in TypeScript offer a powerful way to build smarter error handling patterns that adapt to different scenarios and improve type safety. Whether you are dealing with API errors or validation failures, leveraging conditional types helps catch problems early and write clearer code.

Try experimenting with conditional types for your own error handling needs, and you'll notice how much easier and safer managing errors can become!