Professional TypeScript: error handling, async patterns, and performance optimization.
Error handling patterns, async/await advanced patterns, and performance optimization techniques.
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";
}
}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);
}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");
}
}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");
}
}Custom errors: AppError, ValidationError, NotFoundError
Result type: ok() and err() helpers
Type guards: isAppError, isValidationError
Error handling patterns complete!
class MyError extends Error { constructor() { super(); this.name = "MyError"; } }{ success: true; data: T } | { success: false; error: E }function isX(e: unknown): e is X { return e instanceof X; }Object.setPrototypeOf(this, MyError.prototype) for proper inheritanceReview feedback below
// 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 };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!;
}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;
}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]);
}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() { ... }
}Retry: 3 attempts with backoff
Concurrency: limit 3 parallel
Timeout: 5000ms wrapper
AsyncQueue: controlled execution
Advanced async patterns complete!
delay = baseDelay * Math.pow(2, attempt)Promise.race([promise, timeoutPromise])Review feedback below
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;
}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;
}
}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);
}
};
}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);
}
}
}Memoize: cached fibonacci
Lazy: generator-based iteration
Debounce: 300ms delay
Throttle: 100ms limit
ObjectPool: reuse objects
Performance patterns complete!
function* name() { yield value; }Review feedback below