کار با آرایههای 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
تنها مشکلی که وجود دارد این است که در نسخه ۵٫۲ تایپ اسکریپ، این یک خطا میدهد، اما چرا؟
این اتفاق به این دلیل است که 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
چیزی را که به 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
و هم کار با آن را بسیار آسانتر میکند.