TypeScript آخرین Overload را استنتاج می‌کند

TypeScript هنگام استفاده از توابع overloaded رفتار خاصی دارد.

وقتی سعی می‌کنید یک تایپ را از یک تابع overloaded استنتاج کنید، TypeScript فقط آخرین امضا (signature) را به شما می‌دهد.

من هنگام کار با i18next با این موضوع برخورد کردم. می‌خواستم کلیدهای رشته‌ای (string keys) را به چیزی بهتر تبدیل کنم. هدف من داشتن قابلیت autocomplete و تجربه توسعه‌دهنده (developer experience) بهتر بود. برای انجام این کار، نیاز داشتم تایپ‌های تابع موجود را تغییر دهم.

مشکل: من نیاز داشتم تک‌تک امضاهای فراخوانی (call signature) را از یک تایپ overloaded استخراج کنم.

TypeScript استاندارد راهی برای انجام این کار به شما نمی‌دهد. بیشتر راهکارها از جداول ثابت (hardcoded) استفاده می‌کنند، مثلاً فقط از ۵ یا ۱۰ overload پشتیبانی می‌کنند. من به دنبال راهی بودم که بتواند هر تعداد امضا را مدیریت کند.

من با آزمایش روی تقاطع‌ها (intersections) راه حلی پیدا کردم.

منطق کار به این صورت است:

  • TypeScript از آخرین امضا استنتاج می‌کند.
  • تقاطع‌ها (&) می‌توانند ترتیب امضاها را تغییر دهند.
  • اگر ترتیب را تغییر دهید، آنچه TypeScript هنگام استنتاج می‌بیند نیز تغییر می‌کند.

من کشف کردم که تقاطع دادن یک تایپ overloaded با یکی از امضاهای خودش، آن امضا را به ابتدای لیست منتقل می‌کند.

این کار به من اجازه داد تا یک تایپ بازگشتی (recursive type) ایجاد کنم.

فرآیند به این صورت کار می‌کند:

  1. آخرین امضای قابل مشاهده را استنتاج کنید.
  2. از یک تقاطع (intersection) برای تغییر چیدمان استفاده کنید.
  3. این کار باعث می‌شود امضای بعدی به آخرین امضا تبدیل شود.
  4. این کار را تا زمانی که تمام امضاها را در یک union جمع‌آوری کرده‌اید، تکرار کنید.

وقتی overloadها را به یک union تبدیل کردید، می‌توانید با آن‌ها مانند داده رفتار کنید. می‌توانید آن‌ها را تغییر دهید، تایپ‌های بازگشتی را در Promiseها قرار دهید یا نام آرگومان‌ها را تغییر دهید. پس از تغییر، می‌توانید union را دوباره به یک intersection تبدیل کنید تا تابع overloaded بازیابی شود.

کل فرآیند به این صورت است: Overloads -> Union -> Transform -> Intersection -> Overloads.

این یک ترفند در سیستم تایپ (type-system) است. این یک API رسمی نیست. این روش به نحوه ارزیابی تقاطع‌ها و امضاهای فراخوانی توسط TypeScript بستگی دارد. اگر از این روش در یک کتابخانه استفاده می‌کنید، آن را در نسخه‌های مختلف TypeScript تست کنید.

گاهی اوقات بخش‌های عجیب TypeScript مفیدترین بخش‌ها هستند.

منبع: https://dev.to/svs-nickm/typescript-infers-the-last-overload-so-i-changed-the-order-3018