فهرست سرفصل‌های TypeScript
خانه (Home) معرفی (Introduction) شروع سریع (Get Started) انواع ساده (Simple Types) تعریف صریح و استنتاج نوع (Explicit & Inference) انواع ویژه (Special Types) آرایه ها (Arrays) تاپل ها (Tuples) انواع شیء (Object Types) شمارشی ها (Enums) نام مستعار و اینترفیس ها (Aliases & Interfaces) انواع اتحادی (Union Types) توابع (Functions) تبدیل نوع (Casting) کلاس ها (Classes) جنریک های پایه (Basic Generics) انواع کاربردی (Utility Types) کلیدواژه keyof (Keyof) Null (Null) Definitely Typed (Definitely Typed) به روزرسانی های نسخه 5 (5 Updates) پیکربندی (Configuration) با Node.js (with Node.js) با React (with React) ابزارها (Tooling) انواع پیشرفته (Advanced Types) نگهبان های نوع (Type Guards) انواع شرطی (Conditional Types) انواع نگاشتی (Mapped Types) استنتاج نوع (Type Inference) انواع لیترال (Literal Types) فضای نام (Namespaces) امضاهای ایندکس (Index Signatures) ادغام اعلان ها (Declaration Merging) برنامه نویسی ناهمگام (Async Programming) دکوراتورها (Decorators) در پروژه های JS (in JS Projects) مهاجرت (Migration) مدیریت خطا (Error Handling) بهترین شیوه ها (Best Practices) ادیتور (Editor) تمرین ها (Exercises) آزمون (Quiz) سرفصل دوره (Syllabus) برنامه مطالعه (Study Plan) گواهینامه (Certificate)
نتیجه‌ای برای جستجو یافت نشد.
TypeScript

TypeScript — مدیریت خطا (Error Handling)

آخرین بروزرسانی: 1404/08/14

مدیریت خطا (Error Handling)

«مدیریت خطا (Error Handling)» یعنی کنترل اشتباه ها. با این کار برنامه پایدار می ماند. همچنین پیام ها واضح می شوند و کاربر سردرگم نمی شود.

مدیریت خطای پایه

با بلوک های try و catch شروع کن. اگر چیزی اشتباه شد، خطا را می گیری و واکنش می دهی.

Try/Catch

function divide(a: number, b: number): number {\n  if (b === 0) {\n    throw new Error('Division by zero');\n  }\n  return a / b;\n}\n\ntry {\n  const result = divide(10, 0);\n  console.log(result);\n} catch (error) {\n  console.error('An error occurred:', (error as Error).message);\n}\n

مشاهده در ادیتور

نکته: در TS 4+، متغیر catch از نوع unknown است. بنابراین اول نوع را محدود کن.

ساخت خطاهای سفارشی

برای سناریوهای خاص، از کلاس های خطای سفارشی استفاده کن. این کار خوانایی را بهتر می کند.

کلاس های خطای اختصاصی

class ValidationError extends Error {\n  constructor(message: string, public field?: string) {\n    super(message);\n    this.name = 'ValidationError';\n    Object.setPrototypeOf(this, ValidationError.prototype);\n  }\n}\n\nclass DatabaseError extends Error {\n  constructor(message: string, public code: number) {\n    super(message);\n    this.name = 'DatabaseError';\n    Object.setPrototypeOf(this, DatabaseError.prototype);\n  }\n}\n\nfunction validateUser(user: any): void {\n  if (!user.name) {\n    throw new ValidationError('Name is required', 'name');\n  }\n  if (!String(user.email).includes('@')) {\n    throw new ValidationError('Invalid email format', 'email');\n  }\n}\n

مشاهده در ادیتور

نگهبان نوع برای خطا

«نگهبان نوع (Type Guard)» یعنی تابعی که نوع را تشخیص می دهد. سپس با خیال راحت به ویژگی ها دسترسی می گیری.

Type Guard و استفاده در catch

function isErrorWithMessage(error: unknown): error is { message: string } {\n  return typeof error === 'object' \n    && error !== null \n    && 'message' in error \n    && typeof (error as Record<string, unknown>).message === 'string';\n}\n\nfunction isValidationError(error: unknown): error is ValidationError {\n  return error instanceof ValidationError;\n}\n\ntry {\n  validateUser({});\n} catch (error: unknown) {\n  if (isValidationError(error)) {\n    console.error(`Validation error in ${error.field}: ${error.message}`);\n  } else if (isErrorWithMessage(error)) {\n    console.error('An error occurred:', error.message);\n  } else {\n    console.error('An unknown error occurred');\n  }\n}\n

مشاهده در ادیتور

الگوی Type Assertion

function assertIsError(error: unknown): asserts error is Error {\n  if (!(error instanceof Error)) {\n    throw new Error('Caught value is not an Error instance');\n  }\n}\n\ntry {\n  // ...\n} catch (error) {\n  assertIsError(error);\n  console.error(error.message);\n}\n

مشاهده در ادیتور

خطاهای Async/Await

در کد ناهمگام، فراخوانی های await را در try/catch بگذار. سپس خطاها را مدیریت کن.

نمونه async/await و Promise

interface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\nasync function fetchUser(userId: number): Promise<User> {\n  try {\n    const response = await fetch(`/api/users/${userId}`);\n    if (!response.ok) {\n      throw new Error(`HTTP error! status: ${response.status}`);\n    }\n    const data = await response.json();\n    return data as User;\n  } catch (error) {\n    if (error instanceof Error) {\n      console.error('Failed to fetch user:', error.message);\n    }\n    throw error;\n  }\n}\n\ninterface Post {\n  id: number;\n  title: string;\n}\n\nfunction fetchUserPosts(userId: number): Promise<Post[]> {\n  return fetch(`/api/users/${userId}/posts`)\n    .then((response) => {\n      if (!response.ok) {\n        throw new Error(`HTTP error! status: ${response.status}`);\n      }\n      return response.json();\n    })\n    .then((data) => data as Post[])\n    .catch((error) => {\n      console.error('Failed to fetch posts:', error);\n      return [];\n    });\n}\n

مشاهده در ادیتور

جلوگیری از Rejection بدون مدیریت

// Bad\nfetchData().then((data) => {\n  console.log(data);\n});\n\n// Good\nfetchData()\n  .then((data) => {\n    console.log('Success:', data);\n  })\n  .catch((error) => {\n    console.error('Error:', error);\n  });\n\n// Intentionally ignored\nvoid fetchData().catch(console.error);\n

مشاهده در ادیتور

Error Boundary در React

کامپوننت «Error Boundary» خطاهای درخت کامپوننت ها را می گیرد. سپس رابط را امن نگه می دارد.

نمونه کلاس ErrorBoundary

import React, { Component, ErrorInfo, ReactNode } from 'react';\n\ninterface ErrorBoundaryProps {\n  children: ReactNode;\n  fallback?: ReactNode;\n}\n\ninterface ErrorBoundaryState {\n  hasError: boolean;\n  error?: Error;\n}\n\nclass ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n  public state: ErrorBoundaryState = {\n    hasError: false\n  };\n\n  public static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n    return { hasError: true, error: error };\n  }\n\n  public componentDidCatch(error: Error, errorInfo: ErrorInfo): void {\n    console.error('Uncaught error:', error, errorInfo);\n  }\n\n  public render(): ReactNode {\n    if (this.state.hasError) {\n      return this.props.fallback ?? (\n        <div className=\"error-boundary\">\n          <h2>Something went wrong</h2>\n          <p>{this.state.error?.message}</p>\n          <button onClick={() => this.setState({ hasError: false })}>\n            Try again\n          </button>\n        </div>\n      );\n    }\n    return this.props.children;\n  }\n}\n\nfunction App(): ReactNode {\n  return (\n    <ErrorBoundary fallback={<div>Oops! Something broke.</div>}>\n      <MyComponent />\n    </ErrorBoundary>\n  );\n}\n

مشاهده در ادیتور

بهترین روش ها

همیشه خطا را مدیریت کن

هیچ وقت catch خالی نگذار. حداقل، لاگ کن.

// Bad\ntry {\n  // ...\n} catch {\n  // empty\n}\n\n// Good\ntry {\n  // ...\n} catch (error) {\n  console.error('Operation failed:', error);\n}\n

مشاهده در ادیتور

نوع های مشخص تعریف کن

برای شبکه و اعتبارسنجی، کلاس جدا بساز. سپس پیام مناسب بده.

class NetworkError extends Error {\n  constructor(public status: number, message: string) {\n    super(message);\n    this.name = 'NetworkError';\n  }\n}\n\nclass ValidationErr extends Error {\n  constructor(public field: string, message: string) {\n    super(message);\n    this.name = 'ValidationError';\n  }\n}\n

مشاهده در ادیتور

در سطح درست مدیریت کن

جایی که اطلاعات کافی داری، خطا را بگیر. سپس تجربه کاربر را بهتر کن.

async function getUser(id: string): Promise<User> {\n  const response = await fetch(`/api/users/${id}`);\n  if (!response.ok) {\n    throw new NetworkError(response.status, 'Failed to fetch user');\n  }\n  const data = await response.json();\n  return data as User;\n}\n\nasync function loadUser(): Promise<void> {\n  try {\n    const user = await getUser('123');\n    setUser(user);\n  } catch (error) {\n    if (error instanceof NetworkError) {\n      if (error.status === 404) {\n        showError('User not found');\n      } else {\n        showError('Network error. Please try again later.');\n      }\n    } else {\n      showError('An unexpected error occurred');\n    }\n  }\n}\n

مشاهده در ادیتور

اشتباهات رایج

نادیده گرفتن Rejection

// Bad\nfetchData();\n\n// Good\nfetchData().catch(console.error);\n

مشاهده در ادیتور

بدون محدودسازی نوع در catch

// Bad\ntry {\n  // ...\n} catch (error) {\n  // error: unknown\n  // console.log(error.message);\n}\n\n// Good\ntry {\n  // ...\n} catch (error) {\n  if (error instanceof Error) {\n    console.log(error.message);\n  }\n}\n

مشاهده در ادیتور

قورت دادن خطا

// Bad\nfunction saveData(data: unknown): void {\n  try {\n    database.save(data);\n  } catch {\n    // ignore\n  }\n}\n\n// Better\nfunction saveDataBetter(data: unknown): void {\n  try {\n    database.save(data);\n  } catch (error) {\n    console.error('Failed to save data:', error);\n    showError('Failed to save data. Please try again.');\n  }\n}\n

مشاهده در ادیتور

ادامه مسیر

برای مهاجرت گام به گام، صفحه مهاجرت تایپ اسکریپت را ببین. برای نکته های بیشتر، به بهترین روش ها سر بزن.

جمع بندی سریع

  • در catch نوع را محدود کن.
  • برای سناریوها، خطای سفارشی بساز.
  • در async، همیشه خطا را بگیر.
  • Rejection را رها نکن.
  • در سطح درست مدیریت کن.