آرایه‌های readonly در نسخه ۵.۳ تایپ اسکریپت

کار با آرایه‌های readonly در تایپ اسکریپت ممکن است گاهی اوقات کمی دردسرساز باشد. فرض کنید می‌خواهیم یک آرایه از مسیرها، به عنوان const تعریف کنیم. ما با انجام این کار می‌توانیم از مسیرهایی که برای یک تایپ تعریف کرده‌ایم استفاده مجدد نماییم.

const arrayOfRoutes = [
  { path: "/home", component: Home },
  { path: "/about", component: About },
] as const;
 
type Route = (typeof arrayOfRoutes)[number]["path"];
      
type Route = "/home" | "/about"

اما اگر بخواهیم مطمئن شویم که arrayOfRoutesبا تایپ خاصی مطابقت دارد، چه کاری باید انجام دهیم؟ برای آن می‌توانیم از satisfies استفاده کنیم.

const arrayOfRoutes = [
  { path: "/home", component: Home },
  { path: "/about", component: About },
] as const satisfies {
  path: string;
  component: React.FC;
}[];
// Type is 'readonly' and cannot be
// assigned to a mutable type

تنها مشکلی که وجود دارد این است که در نسخه ۵٫۲ تایپ اسکریپ، این یک خطا می‌دهد، اما چرا؟

مقایسه آرایه‌های readonly و آرایه‌های قابل تغییر

این اتفاق به این دلیل است که arrayOfRoutesیک آرایه readonly است و ما نمی‌توانیم یک آرایه قابل تغییر را با یک readonly ایجاد کنیم. بنابراین، راه حل این مشکل این است که تایپ مورد نظرمان را به یک آرایهreadonlyتبدیل نماییم:

const arrayOfRoutes = [
  { path: "/home", component: Home },
  { path: "/about", component: About },
] as const satisfies readonly {
  path: string;
  component: React.FC;
}[];
 
// No more error!

اکنون که از یک آرایه readonly استفاده می‌کنیم، هیچ خطایی ایجاد نمی‌شود.

پارامترهای تایپ Const

هنگام استفاده از پارامترهای تایپ const نیز همین امر صادق است، حتی ممکن است کمی حساسیت بیشتری نسبت به حالت قبل داشته باشد.

در این موقعیت، constچیزی را که به Tمنتقل شده است، استنتاج می‌کند که گویی as constاست. اما اگر بخواهیم آن را با یک آرایه محدود کنیم، کار نمی‌کند.

const returnWhatIPassIn = <const T extends any[]>(t: T) => {
  return t;
};
 
// result is any[] in TS 5.2!
const result = returnWhatIPassIn(["a", "b", "c"]);

راه حل این مشکل برای نسخه‌های قبل از ۵٫۳ تایپ اسکریپت، این بود که readonlyبه پارامتر type اضافه کنیم.

const returnWhatIPassIn = <const T extends readonly any[]>(
  t: T
) => {
  return t;
};
 
// result is ['a', 'b', 'c']!
const result = returnWhatIPassIn(["a", "b", "c"]);

اما برای اینکه بتوانیم این مشکل را پیدا کرده و برطرف نماییم باید دانش عمیق در مورد نحوه عملکرد پارامترهای تایپ const داشته باشیم که البته کار دشواری است.

چگونه نسخه ۵٫۳ تایپ اسکریپت آن را رفع کرده است؟

از نسخه ۵٫۳، تایپ اسکریپت قوانین مربوط به آرایه‌های readonly را کاهش داده است. بنابراین در این دو موقعیت، تایپ اسکریپت مفیدتر عمل می‌کند. اکنون کلمه کلیدی satisfies به ما این امکان را می‌دهد تا مشکل آرایه‌های readonly را برطرف نماییم:

// This would error in 5.2, but is allowed in 5.3!
const array = ["a", "b", "c"] as const satisfies string[];
       
const array: ["a", "b", "c"]

حال پارامترهای تایپ Const به جای پیش‌فرض بودن به محدودیت‌های خود، تایپ ارسال شده را استنباط می‌کنند:

const returnWhatIPassIn = <const T extends any[]>(t: T) => {
  return t;
};
 
// result is any[] in TS 5.2, but ['a', 'b', 'c'] in 5.3
const result = returnWhatIPassIn(["a", "b", "c"]);
        
const result: ["a", "b", "c"]

باید به این نکته توجه داشته باشیم که یک تفاوت کوچک وجود دارد. اگر بخواهید readonly string[]را به جای string[]مشخص کنیم، یک آرایه readonly را دریافت خواهیم کرد.

بنابراین اگر قصد داریم یک آرایه readonly بازگردانده شود، باید readonly را مشخص نماییم.

// This would error in 5.2, but is allowed in 5.3!
const array = [
       
const array: readonly ["a", "b", "c"]
  "a",
  "b",
  "c",
] as const satisfies readonly string[];
 
const returnWhatIPassIn = <const T extends readonly any[]>(
  t: T
) => {
  return t;
};
 
// result is any[] in TS 5.2, but ['a', 'b', 'c'] in 5.3
const result = returnWhatIPassIn(["a", "b", "c"]);
        
const result: readonly ["a", "b", "c"]

این موضوع یک پیشرفت بسیار بزرگ است که هم پارامترهای تایپ constو هم کار با آن را بسیار آسان‌تر می‌کند.

دیدگاه‌ها:

افزودن دیدگاه جدید