فهرست سرفصل‌های 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 — بهترین شیوه ها (Best Practices)

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

بهترین شیوه ها (Best Practices)

در «بهترین شیوه های تایپ اسکریپت»، هدف ما کد تمیز و ایمن است. «ایمن از نوع (Type-safe)» یعنی خطاها زودتر گیر می افتند. بنابراین نگهداری آسان تر می شود و تیم راحت تر پیش می رود.

پیکربندی پروژه

حالت «سخت گیر (strict)» را روشن کن. سپس چند گزینه پیشنهادی را هم فعال کن.

فعال سازی Strict Mode

// tsconfig.json\n{\n  \"compilerOptions\": {\n    /* Enable all strict type-checking options */\n    \"strict\": true,\n    /* Additional recommended settings */\n    \"target\": \"ES2020\",\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true\n  }\n}\n

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

سخت گیری های بیشتر

{\n  \"compilerOptions\": {\n    \"noImplicitAny\": true,\n    \"strictNullChecks\": true,\n    \"strictFunctionTypes\": true,\n    \"strictBindCallApply\": true,\n    \"strictPropertyInitialization\": true,\n    \"noImplicitThis\": true,\n    \"alwaysStrict\": true\n  }\n}\n

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

بهترین ها برای سیستم نوع

«استنباط نوع (Type Inference)» یعنی TS خودش نوع را حدس بزند. جاهای واضح، بگذار خودش حدس بزند.

به استنباط اعتماد کن

// Bad\nconst name: string = 'John';\n\n// Good\nconst name = 'John';\n\n// Bad\nfunction add(a: number, b: number): number {\n  return a + b;\n}\n\n// Good\nfunction add(a: number, b: number) {\n  return a + b;\n}\n

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

Annotation دقیق در APIها

// Bad\nfunction processUser(user: any) {\n  return (user as any).name.toUpperCase();\n}\n\n// Good\ninterface User {\n  id: number;\n  name: string;\n  email?: string;\n}\n\nfunction processUser(user: User): string {\n  return user.name.toUpperCase();\n}\n

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

interface در برابر type

interface User {\n  id: number;\n  name: string;\n}\n\ninterface AdminUser extends User {\n  permissions: string[];\n}\n\ntype UserRole = 'admin' | 'editor' | 'viewer';\n\ntype UserId = number | string;\n\ntype ReadonlyUser = Readonly<User>;\n\ntype Point = [number, number];\n

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

تا جای ممکن از any دوری کن

// Bad\nfunction logValue(value: any): void {\n  console.log((value as any).toString());\n}\n\n// Better\nfunction logValue<T>(value: T): void {\n  console.log(String(value));\n}\n\n// Best\nfunction logString(value: string): void {\n  console.log(value.toUpperCase());\n}\n\nfunction logUnknown(value: unknown): void {\n  if (typeof value === 'string') {\n    console.log(value.toUpperCase());\n  } else {\n    console.log(String(value));\n  }\n}\n

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

سازمان دهی کد

ماژول ها را تفکیک کن. سپس فایل ها را نام گذاری منظم کن.

چینش ماژول ها

// user/user.model.ts\nexport interface User {\n  id: string;\n  name: string;\n  email: string;\n}\n\n// user/user.service.ts\nimport { User } from './user.model';\n\nexport class UserService {\n  private users: User[] = [];\n\n  addUser(user: User): void {\n    this.users.push(user);\n  }\n\n  getUser(id: string): User | undefined {\n    return this.users.find((user) => {\n      return user.id === id;\n    });\n  }\n}\n\n// user/index.ts\nexport * from './user.model';\nexport * from './user.service';\n

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

الگوی نام گذاری فایل

// Good\n// user.service.ts\n// user.model.ts\n// user.controller.ts\n// user.component.ts\n// user.utils.ts\n// user.test.ts\n\n// Bad\n// UserService.ts\n// user_service.ts\n// userService.ts\n

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

توابع و متدها

ورودی ها و خروجی ها را دقیق مشخص کن. سپس از پارامترهای پیش فرض و rest کمک بگیر.

پارامترها و خروجی ها

// Bad\nfunction process(user: any, notify: any): void {\n  notify((user as any).name);\n}\n\n// Good\ninterface User {\n  id: string;\n  name: string;\n}\n\nfunction processUser(user: User, notify: (message: string) => void): void {\n  notify(`Processing user: ${user.name}`);\n}\n\nfunction createUser(name: string, role: string = 'viewer', isActive: boolean = true): {\n  name: string;\n  role: string;\n  isActive: boolean;\n} {\n  return { name: name, role: role, isActive: isActive };\n}\n\nfunction sum(...numbers: number[]): number {\n  return numbers.reduce((total, num) => {\n    return total + num;\n  }, 0);\n}\n

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

کوچک سازی مسئولیت ها

// Better\ninterface UserData {\n  name: string;\n  email: string;\n}\n\ninterface ProcessedUserData extends UserData {\n  createdAt: Date;\n}\n\nfunction validateUserData(data: unknown): UserData {\n  if (!data || typeof data !== 'object') {\n    throw new Error('Invalid user data');\n  }\n  return data as UserData;\n}\n\nfunction processUserData(userData: UserData): ProcessedUserData {\n  return {\n    ...userData,\n    name: userData.name.trim(),\n    createdAt: new Date()\n  };\n}\n

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

الگوهای Async/Await

در ناهمگام ها، خطا را مدیریت کن. سپس درخواست های مستقل را موازی کن.

استفاده درست از Async/Await

async function fetchData<T>(url: string): Promise<T> {\n  try {\n    const response = await fetch(url);\n    if (!response.ok) {\n      throw new Error(`HTTP error! status: ${response.status}`);\n    }\n    return await response.json() as T;\n  } catch (error) {\n    console.error('Failed to fetch data:', error);\n    throw error;\n  }\n}\n\nasync function fetchMultipleData<T>(urls: string[]): Promise<T[]> {\n  try {\n    const promises = urls.map((u) => {\n      return fetchData<T>(u);\n    });\n    return await Promise.all(promises);\n  } catch (error) {\n    console.error('One or more requests failed:', error);\n    throw error;\n  }\n}\n\ninterface User {\n  id: string;\n  name: string;\n  email: string;\n}\n\nasync function getUserData(userId: string): Promise<User> {\n  return fetchData<User>(`/api/users/${userId}`);\n}\n

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

پرهیز از تو در تویی

async function processUser(userId: string): Promise<{ user: unknown; latestOrder: unknown; items: unknown[] } | null> {\n  const user = await getUser(userId);\n  if (!user) {\n    return null;\n  }\n  const orders = await getOrders(userId);\n  if (orders.length === 0) {\n    return { user: user, latestOrder: null, items: [] };\n  }\n  const latestOrder = orders[0];\n  const items = await getOrderItems(latestOrder.id);\n  return { user: user, latestOrder: latestOrder, items: items };\n}\n

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

تست و کیفیت

وابستگی ها را تزریق کن. سپس توابع خالص بساز تا تست پذیر شوند.

کد تست پذیر

interface PaymentGateway {\n  charge(amount: number): Promise<boolean>;\n}\n\nclass PaymentProcessor {\n  constructor(private paymentGateway: PaymentGateway) {}\n\n  async processPayment(amount: number): Promise<boolean> {\n    if (amount <= 0) {\n      throw new Error('Amount must be greater than zero');\n    }\n    return this.paymentGateway.charge(amount);\n  }\n}\n

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

Type Testing نمونه ای

// @ts-expect-error\nconst invalidUser: { id: number; name: string } = { id: -1, name: 'Test' };\n\nfunction assertIsString(value: unknown): asserts value is string {\n  if (typeof value !== 'string') {\n    throw new Error('Not a string');\n  }\n}\n\ntype IsString<T> = T extends string ? true : false;\ntype Test1 = IsString<string>;\ntype Test2 = IsString<number>;\n

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

نکات عملکردی

«واردات فقط-نوع (Type-only imports)» به درخت بُری کمک می کند. همچنین کُد سبک تر می شود.

type-only import/export

import type { User } from './api';\nimport { fetchUser } from './api';\n\nexport type { User };\nexport { fetchUser };\n\n// tsconfig: \"isolatedModules\": true\n

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

از نوع های بیش ازحد پیچیده دوری کن

// Better: استفاده از Utility Types\ninterface UserProfile {\n  name: string;\n  email: string;\n}\n\ninterface UserPreferences {\n  notifications: boolean;\n}\n\ninterface User {\n  id: string;\n  profile: UserProfile;\n  preferences?: UserPreferences;\n}\n\nconst updateUser = (updates: Partial<User>): void => {\n  // ...\n};\n

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

const assertion برای نوع های دقیق

const colors = ['red', 'green', 'blue'] as const;\ntype Color = typeof colors[number];\n\nconst config = {\n  apiUrl: 'https://api.example.com',\n  timeout: 5000,\n  features: ['auth', 'notifications']\n} as const;\n

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

خطاهای رایج

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

زیاده روی در any

// Bad\nfunction process(data: any): unknown {\n  return (data as any).map((item: any) => {\n    return item.name;\n  });\n}\n\n// Better\nfunction process<T extends { name: string }>(items: T[]): string[] {\n  return items.map((item) => {\n    return item.name;\n  });\n}\n

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

نادیده گرفتن Strict Mode

{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"noImplicitAny\": true,\n    \"strictNullChecks\": true,\n    \"strictFunctionTypes\": true,\n    \"strictBindCallApply\": true,\n    \"strictPropertyInitialization\": true,\n    \"noImplicitThis\": true,\n    \"alwaysStrict\": true\n  }\n}\n

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

بی توجهی به نگهبان نوع

function isString(value: unknown): value is string {\n  return typeof value === 'string';\n}\n\nfunction process(input: string | number): string {\n  if (isString(input)) {\n    return input.toUpperCase();\n  } else {\n    return input.toFixed(2);\n  }\n}\n\nif (typeof value === 'string') {\n  // value is string\n}\n\nif (value instanceof Date) {\n  // value is Date\n}\n\nif ('id' in (user as object)) {\n  // user has id property\n}\n

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

عدم مدیریت null/undefined

function getLength(str: string | null): number {\n  if (str === null) {\n    return 0;\n  }\n  return str.length;\n}\n\nfunction getLengthSafe(str: string | null): number {\n  return str?.length ?? 0;\n}\n\ninterface User {\n  profile?: {\n    name?: string;\n  };\n}\n\nconst user: User = {};\nconst name = user.profile?.name ?? 'Anonymous';\n

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

جمع بندی سریع

  • strict را روشن نگه دار.
  • از any فاصله بگیر.
  • استنباط نوع را جدی بگیر.
  • async را با خطا مدیریت کن.
  • ماژول ها را تمیز بچین.