TypeScript Programming Labs

Professional TypeScript: error handling, async patterns, and performance optimization.

Professional Level - Module 9

Error handling patterns, async/await advanced patterns, and performance optimization techniques.

Lab 25: Error Handling Patterns
Professional
Coding Challenge
Your Task: Master TypeScript error handling patterns including custom errors, Result types, and type-safe error handling.

Detailed Requirements:
1. Custom error classes:
class AppError extends Error { constructor( message: string, public code: string, public statusCode: number = 500 ) { super(message); this.name = "AppError"; Object.setPrototypeOf(this, AppError.prototype); } } class ValidationError extends AppError { constructor(public field: string, message: string) { super(message, "VALIDATION_ERROR", 400); this.name = "ValidationError"; } } class NotFoundError extends AppError { constructor(resource: string) { super(\`\${resource} not found\`, "NOT_FOUND", 404); this.name = "NotFoundError"; } }

2. Result type pattern (no exceptions):
type Result<T, E = Error> = | { success: true; data: T } | { success: false; error: E }; function ok<T>(data: T): Result<T, never> { return { success: true, data }; } function err<E>(error: E): Result<never, E> { return { success: false, error }; } function divide(a: number, b: number): Result<number, string> { if (b === 0) return err("Division by zero"); return ok(a / b); }

3. Type guards for errors:
function isAppError(error: unknown): error is AppError { return error instanceof AppError; } function isValidationError(error: unknown): error is ValidationError { return error instanceof ValidationError; } function handleError(error: unknown) { if (isValidationError(error)) { console.log(\`Validation failed for \${error.field}\`); } else if (isAppError(error)) { console.log(\`App error: \${error.code}\`); } else { console.log("Unknown error"); } }

4. Try-catch with type narrowing:
async function fetchUser(id: string): Promise<User> { try { const response = await fetch(\`/api/users/\${id}\`); if (!response.ok) { throw new NotFoundError("User"); } return await response.json(); } catch (error) { if (error instanceof NotFoundError) { throw error; } throw new AppError("Failed to fetch user", "FETCH_ERROR"); } }

Expected Output:
Custom errors: AppError, ValidationError, NotFoundError Result type: ok() and err() helpers Type guards: isAppError, isValidationError Error handling patterns complete!

Requirements Checklist

Create custom error class extending Error
Create specialized error subclasses
Implement Result type pattern
Create ok() and err() helper functions
Create error type guards
Handle errors with type narrowing
Output
// Click "Run Code" to compile and execute
Hints & Tips
� Custom error: class MyError extends Error { constructor() { super(); this.name = "MyError"; } }
� Result type: { success: true; data: T } | { success: false; error: E }
� Type guard: function isX(e: unknown): e is X { return e instanceof X; }
� Use Object.setPrototypeOf(this, MyError.prototype) for proper inheritance
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 26: Advanced Async Patterns
Professional
Coding Challenge
Your Task: Master advanced async/await patterns including concurrency control, retry logic, and typed async utilities.

Detailed Requirements:
1. Typed Promise utilities:
// Promise.all with proper typing async function fetchAll<T>( urls: string[], fetcher: (url: string) => Promise<T> ): Promise<T[]> { return Promise.all(urls.map(fetcher)); } // Promise.allSettled with result handling type SettledResult<T> = | { status: "fulfilled"; value: T } | { status: "rejected"; reason: unknown };

2. Retry with exponential backoff:
interface RetryOptions { maxAttempts: number; baseDelay: number; maxDelay: number; } async function retry<T>( fn: () => Promise<T>, options: RetryOptions ): Promise<T> { let lastError: Error; for (let i = 0; i < options.maxAttempts; i++) { try { return await fn(); } catch (error) { lastError = error as Error; const delay = Math.min( options.baseDelay * Math.pow(2, i), options.maxDelay ); await sleep(delay); } } throw lastError!; }

3. Concurrency limiter:
async function mapWithConcurrency<T, R>( items: T[], fn: (item: T) => Promise<R>, concurrency: number ): Promise<R[]> { const results: R[] = []; const executing: Promise<void>[] = []; for (const item of items) { const promise = fn(item).then(result => { results.push(result); }); executing.push(promise); if (executing.length >= concurrency) { await Promise.race(executing); } } await Promise.all(executing); return results; }

4. Timeout wrapper:
function withTimeout<T>( promise: Promise<T>, ms: number ): Promise<T> { const timeout = new Promise<never>((_, reject) => { setTimeout(() => reject(new Error("Timeout")), ms); }); return Promise.race([promise, timeout]); }

5. Async queue:
class AsyncQueue<T> { private queue: Array<() => Promise<T>> = []; private running = 0; constructor(private concurrency: number) {} async add(task: () => Promise<T>): Promise<T> { return new Promise((resolve, reject) => { this.queue.push(async () => { try { resolve(await task()); } catch (e) { reject(e); } }); this.process(); }); } private async process() { ... } }

Expected Output:
Retry: 3 attempts with backoff Concurrency: limit 3 parallel Timeout: 5000ms wrapper AsyncQueue: controlled execution Advanced async patterns complete!

Requirements Checklist

Create typed Promise utilities
Implement retry with backoff
Create concurrency limiter
Implement timeout wrapper
Create AsyncQueue class
Test async patterns
Output
// Click "Run Code" to compile and execute
Hints & Tips
� Retry: Use for loop with try/catch and exponential delay
� Backoff: delay = baseDelay * Math.pow(2, attempt)
� Timeout: Promise.race([promise, timeoutPromise])
� Concurrency: Track executing promises, use Promise.race
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 27: Performance & Optimization
Professional
Coding Challenge
Your Task: Master TypeScript performance patterns including memoization, lazy evaluation, and efficient data structures.

Detailed Requirements:
1. Generic memoization:
function memoize<T extends (...args: any[]) => any>( fn: T, keyFn?: (...args: Parameters<T>) => string ): T { const cache = new Map<string, ReturnType<T>>(); return ((...args: Parameters<T>): ReturnType<T> => { const key = keyFn ? keyFn(...args) : JSON.stringify(args); if (cache.has(key)) { return cache.get(key)!; } const result = fn(...args); cache.set(key, result); return result; }) as T; }

2. Lazy evaluation with generators:
function* lazyMap<T, R>( iterable: Iterable<T>, fn: (item: T) => R ): Generator<R> { for (const item of iterable) { yield fn(item); } } function* lazyFilter<T>( iterable: Iterable<T>, predicate: (item: T) => boolean ): Generator<T> { for (const item of iterable) { if (predicate(item)) yield item; } }

3. Debounce and throttle:
function debounce<T extends (...args: any[]) => any>( fn: T, delay: number ): (...args: Parameters<T>) => void { let timeoutId: ReturnType<typeof setTimeout>; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => fn(...args), delay); }; } function throttle<T extends (...args: any[]) => any>( fn: T, limit: number ): (...args: Parameters<T>) => void { let inThrottle = false; return (...args) => { if (!inThrottle) { fn(...args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }

4. Object pooling:
class ObjectPool<T> { private available: T[] = []; private inUse = new Set<T>(); constructor( private factory: () => T, private reset: (obj: T) => void, private initialSize: number = 10 ) { for (let i = 0; i < initialSize; i++) { this.available.push(factory()); } } acquire(): T { const obj = this.available.pop() ?? this.factory(); this.inUse.add(obj); return obj; } release(obj: T): void { if (this.inUse.delete(obj)) { this.reset(obj); this.available.push(obj); } } }

Expected Output:
Memoize: cached fibonacci Lazy: generator-based iteration Debounce: 300ms delay Throttle: 100ms limit ObjectPool: reuse objects Performance patterns complete!

Requirements Checklist

Implement generic memoize function
Create lazy evaluation with generators
Implement debounce function
Implement throttle function
Create ObjectPool class
Test performance utilities
Output
// Click "Run Code" to compile and execute
Hints & Tips
� Memoize: Use Map with JSON.stringify(args) as key
� Generator: function* name() { yield value; }
� Debounce: clearTimeout then setTimeout
� Throttle: Use boolean flag with setTimeout
� Pool: Track available and in-use objects
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

TypeScript Professional Level Complete!

Outstanding work! You've mastered error handling, async patterns, and performance optimization. You're now a TypeScript professional!