Error Handling & Debugging Interview Questions
Comprehensive error handling & debugging interview questions and answers for TypeScript. Prepare for your next job interview with expert guidance.
Questions Overview
1. How do you implement custom error types in TypeScript?
Basic2. What are union types in error handling and how do you use them?
Moderate3. How do you handle async errors in TypeScript?
Moderate4. What are type guards in error handling?
Advanced5. How do you use the 'unknown' type for error handling?
Moderate6. What debugging tools and techniques are available for TypeScript?
Basic7. How do you implement error boundaries in TypeScript?
Advanced8. What is the role of source maps in TypeScript debugging?
Basic9. How do you handle type assertions in error handling?
Advanced10. What are the best practices for error handling in TypeScript?
Moderate11. How do you implement error logging in TypeScript?
Moderate12. What is the difference between throw and reject in TypeScript?
Basic13. How do you debug TypeScript tests?
Moderate14. How do you implement retry logic with error handling?
Advanced15. What are conditional types in error handling?
Advanced16. How do you handle Promise rejections in TypeScript?
Moderate17. What are discriminated unions in error handling?
Advanced18. How do you debug memory leaks in TypeScript applications?
Advanced19. What are error handling patterns for TypeScript decorators?
Advanced20. How do you implement circuit breakers in TypeScript?
Advanced1. How do you implement custom error types in TypeScript?
BasicCustom error types can be created by extending the Error class. Example: class ValidationError extends Error { constructor(message: string) { super(message); this.name = 'ValidationError'; Object.setPrototypeOf(this, ValidationError.prototype); } } This allows for type-safe error handling and custom error properties.
2. What are union types in error handling and how do you use them?
ModerateUnion types in error handling allow functions to return either a success value or an error type. Example: type Result<T> = { success: true; data: T; } | { success: false; error: Error; }. This pattern enables type-safe error handling without throwing exceptions: function process(): Result<string> { try { return { success: true, data: 'processed' }; } catch (e) { return { success: false, error: e instanceof Error ? e : new Error(String(e)) }; } }
3. How do you handle async errors in TypeScript?
ModerateAsync errors can be handled using try-catch with async/await or .catch() with Promises. Example: async function handleAsync() { try { await riskyOperation(); } catch (error) { if (error instanceof NetworkError) { // Handle network errors } else if (error instanceof ValidationError) { // Handle validation errors } throw error; // Re-throw unhandled errors } }
4. What are type guards in error handling?
AdvancedType guards help narrow down error types for proper handling. Example: function isNetworkError(error: unknown): error is NetworkError { return error instanceof NetworkError; } try { // risky operation } catch (error) { if (isNetworkError(error)) { console.log(error.statusCode); // TypeScript knows error is NetworkError } }
5. How do you use the 'unknown' type for error handling?
ModerateThe 'unknown' type is safer than 'any' for error handling as it requires type checking before use. Example: function handleError(error: unknown) { if (error instanceof Error) { console.log(error.message); } else if (typeof error === 'string') { console.log(error); } else { console.log('Unknown error occurred'); } }
6. What debugging tools and techniques are available for TypeScript?
BasicTypeScript debugging tools include: 1) Source maps for debugging compiled code, 2) VS Code's built-in debugger, 3) Chrome DevTools with source maps, 4) debugger statement, 5) console methods (log, warn, error, trace), 6) TypeScript compiler flags like --noEmitOnError, 7) Jest debugger for testing. Configuration in launch.json: { 'type': 'node', 'request': 'launch', 'sourceMaps': true }
7. How do you implement error boundaries in TypeScript?
AdvancedError boundaries are implemented using class components with error handling lifecycle methods. Example: class ErrorBoundary extends React.Component<Props, State> { static getDerivedStateFromError(error: Error): State { return { hasError: true, error }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { logErrorToService(error, errorInfo); } } This catches and handles errors in child components.
8. What is the role of source maps in TypeScript debugging?
BasicSource maps enable debugging of TypeScript code directly, even though the browser runs compiled JavaScript. They map positions in the compiled code to the original TypeScript. Enable with 'sourceMap: true' in tsconfig.json. This allows setting breakpoints in TypeScript files and seeing TypeScript variables during debugging.
9. How do you handle type assertions in error handling?
AdvancedType assertions should be used carefully in error handling to maintain type safety. Example: function handleError(error: unknown) { if (error instanceof Error) { const customError = error as CustomError; // Only assert after instanceof check if (customError.code) { // Handle custom error } } }
10. What are the best practices for error handling in TypeScript?
ModerateBest practices include: 1) Use custom error classes for specific error types, 2) Implement type-safe error handling with union types, 3) Always check error types before using their properties, 4) Use async/await with try-catch for async operations, 5) Implement proper error logging and monitoring, 6) Use error boundaries in React applications, 7) Avoid using 'any' for error types, prefer 'unknown'.
11. How do you implement error logging in TypeScript?
ModerateError logging can be implemented using a centralized error logging service. Example: class ErrorLogger { static log(error: Error, context?: object) { const errorLog = { timestamp: new Date(), name: error.name, message: error.message, stack: error.stack, context }; // Send to logging service or store locally console.error(errorLog); } }
12. What is the difference between throw and reject in TypeScript?
Basicthrow is used for synchronous error handling and immediately stops execution, while reject is used in Promises for asynchronous error handling. Example: function sync() { throw new Error('Sync error'); } async function async() { return Promise.reject(new Error('Async error')); } throw creates an exception, reject creates a rejected Promise.
13. How do you debug TypeScript tests?
ModerateTypeScript tests can be debugged using: 1) Jest's debugger with ts-jest, 2) VS Code's debug configuration for tests, 3) Chrome DevTools with karma. Example launch.json: { 'type': 'node', 'request': 'launch', 'name': 'Debug Tests', 'program': '${workspaceFolder}/node_modules/jest/bin/jest', 'args': ['--runInBand'] }
14. How do you implement retry logic with error handling?
AdvancedRetry logic can be implemented using recursive functions or libraries with proper error handling. Example: async function retryOperation<T>(operation: () => Promise<T>, maxRetries: number): Promise<T> { try { return await operation(); } catch (error) { if (maxRetries > 0) { await delay(1000); return retryOperation(operation, maxRetries - 1); } throw error; } }
15. What are conditional types in error handling?
AdvancedConditional types help create type-safe error handling patterns. Example: type ErrorResponse<T> = T extends Error ? { error: T; data: null; } : { error: null; data: T; }; function handleResult<T>(result: T): ErrorResponse<T> { return result instanceof Error ? { error: result, data: null } : { error: null, data: result }; }
16. How do you handle Promise rejections in TypeScript?
ModeratePromise rejections can be handled using .catch(), try-catch with async/await, or global handlers. Example: window.onunhandledrejection = (event: PromiseRejectionEvent) => { console.error('Unhandled promise rejection:', event.reason); event.preventDefault(); }; This ensures all rejected Promises are handled.
17. What are discriminated unions in error handling?
AdvancedDiscriminated unions provide type-safe error handling by using a common property to discriminate between success and error states. Example: type Result<T> = { kind: 'success'; value: T; } | { kind: 'error'; error: Error; }; This enables exhaustive checking of all possible states.
18. How do you debug memory leaks in TypeScript applications?
AdvancedMemory leaks can be debugged using: 1) Chrome DevTools Memory panel, 2) Heap snapshots, 3) Memory allocation timeline, 4) Node.js --inspect flag. Example: Taking heap snapshots: const heapSnapshot = require('heapdump'); heapSnapshot.writeSnapshot(`${Date.now()}.heapsnapshot`); Then analyze using Chrome DevTools.
19. What are error handling patterns for TypeScript decorators?
AdvancedDecorators can implement error handling through method wrapping. Example: function catchErrors() { return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const original = descriptor.value; descriptor.value = async function(...args: any[]) { try { return await original.apply(this, args); } catch (error) { ErrorLogger.log(error); throw error; } }; }; }
20. How do you implement circuit breakers in TypeScript?
AdvancedCircuit breakers prevent cascading failures by stopping operations after too many errors. Example: class CircuitBreaker { private failures = 0; private readonly threshold = 5; async execute<T>(operation: () => Promise<T>): Promise<T> { if (this.failures >= this.threshold) { throw new Error('Circuit breaker open'); } try { const result = await operation(); this.failures = 0; return result; } catch (error) { this.failures++; throw error; } } }