دو تایپ Unknown و Never

27 اسفند 1398
دو تایپ Unknown و Never

تایپ Unknown در TypeScript

تا این قسمت اکثر تایپ ها را یاد گرفته ایم اما 2 تایپ اصلی دیگر باقی مانده اند که آشنایی با آن ها مهم است. این تایپ ها مانند تایپ های دیگر رایج نیستند اما هنوز هم کاربردهای خودشان را دارند. اولین این تایپ ها Unknown (به معنی «ناشناخته») است. به طور مثال فرض کنید متغیری به شکل زیر داشته باشم:

let userInput: unknown;

ما در اینجا فرض کرده ایم که نمی دانیم کاربر قرار است چه چیزی را وارد این قسمت کند بنابراین تایپ unknown یا ناشناخته را به آن داده ایم. همانطور که مشخص است ما می توانیم هر مقداری را بدون خطا در unknown ذخیره کنیم:

let userInput: unknown;

userInput = 5;
userInput = 'Max';

اگر در حال حاضر tsc app.ts را اجرا کنم، تایپ اسکریپت بدون هیچ خطایی کد من را کامپایل می کند. شاید از خودتان بپرسید تفاوت any و unknown چیست. بله، این دو تایپ شباهت بسیار زیادی به هم دارند اما از یک نظر تفاوت جالبی دارند. فرض کنید متغیر دیگری داشته باشیم که تایپ آن string باشد:

let userName: string;

اگر چنین متغیری را به userInput انتساب دهیم، با خطا روبرو می شویم:

let userInput: unknown;
let userName: string;

userInput = 5;
userInput = 'Max';
userName = userInput;

در کد بالا تایپ اسکریپت سریعا زیر خط آخر کد، خط قرمز کشیده و از ما خطا می گیرد:

خطای تایپ اسکریپت برای تایپ unknown
خطای تایپ اسکریپت برای تایپ unknown

فکر می کنم دلیل این خطا برای شما هم واضح باشد. متغیر userName مقداری رشته ای می خواهد اما معلوم نیست userInput رشته ای باشد یا مقدار دیگری بگیرد! نکته ی جالب تر اینجاست که اگر userInput را روی any قرار بدهم هیچ خطایی دریافت نمی کنم:

let userInput: any;
let userName: string;

userInput = 5;
userInput = 'Max';
userName = userInput;

این کد برای تایپ اسکریپت کاملا صحیح است! چرا؟ به دلیل اینکه any منعطف ترین تایپ در زبان تایپ اسکریپت است و تمام type check ها را از کار می اندازد. به عبارت دیگر اگر برای متغیر یا پارامتری از any استفاده کنید، قابلیت مشخص کردن تایپ را برای آن از دست می دهید چرا که تایپ اسکریپت دیگر زحمت چک کردن آن را به خود نمی دهد. در صورتی که unknown کمی سخت گیرانه تر عمل می کند و مثلا در کد قبلی اگر بخواهیم خطا را حل کنیم باید صریحا چک کنیم و مطمئن شویم که نوع userInput رشته ای است:

let userInput: unknown;
let userName: string;

userInput = 5;
userInput = 'Max';
if (typeof userInput === 'string') {
  userName = userInput;
}

با انجام این کار دیگر خطایی را نمی بینیم و می توانیم به راحتی کدها را کامپایل کنیم. حالا تایپ اسکریپت می فهمد که من از نوع متغیر userInput مطمئن هستم و با تصمیم آگاهانه ی خودم آن را برابر username قرار داده ام. قانون کلی بدین صورت است که اگر از unknown استفاده می کنید، برای انتساب آن ها به متغیر های دیگر باید به صورت صریح از یک شرط if استفاده کنید تا به تایپ اسکریپت اعلام کنید که از نوع آن مطمئن هستید.

به همین خاطر است که در حالت کلی unknown انتخاب بهتری از any است و به شما پیشنهاد می شود که اگر از نوع متغیر یا پارامتر خود مطمئن نیستید، به جای any تایپ unknown را انتخاب کنید. البته این به معنی استفاده ی بی رویه از unknown نیست و هنوز هم باید تا حد ممکن از استفاده از آن دوری کنید. به طور مثال یکی از روش های بهتر استفاده از union type ها می باشد.

تایپ Never در TypeScript

تایپ بعدی ما never (به معنای «هیچ وقت») است. never در TypeScript یکی دیگر از تایپ هایی است که می تواند توسط توابع برگردانده شود. به طور مثال فرض کنید تابعی به شکل زیر داشته باشیم:

function generateError(message: string, code: number) {

}

وظیفه ی این تابع تولید خطا است و دو پارامتر می گیرد که اولی رشته ای (پیام خطا) و دومی عددی (کد خطا) می باشد. من می خواهم درون این تابع یک خطا را throw کنم و همانطور که می دانیم این قابلیت در جاوا اسکریپت موجود است. ما می توانیم هر چیزی را که خواستیم به عنوان خطا throw کنیم:

function generateError(message: string, code: number) {
  throw { message: message, errorCode: code };
}

همانطور که می بینید من یک شیء را throw کرده ام که دو خصوصیت message و errorCode دارد و مقدار این خصوصیات برابر پارامترهای پاس داده شده به تابع هستند. حالا مثل هر تابع دیگری آن را صدا می زنیم:

function generateError(message: string, code: number) {
  throw { message: message, errorCode: code };
}

generateError('An error occurred!', 500);

نتیجه ی صدا زدن این تابع یک خطا در کنسول مرورگر است:

پرتاب شدن خطا در کنسول مرورگر
پرتاب شدن خطا در کنسول مرورگر

داشتن توابع کمکی به این شکل شاید در نظر اول بدون فایده باشد اما در پروژه های بزرگ و واقعی همیشه از چنین توابعی استفاده می شود. در این نوع پروژه ها پرتاب کردن خطاها به صورت دستی کار خسته کننده ای است، مخصوصا که خطاهای این نوع پروژه ها مثل کد بالا یک خطی و ساده نیستند و انواع و اقسام اطلاعات و تنظیمات دیگر را همراه خود دارند.

قبلا یاد گرفته اید که تابع بالا به دلیل نداشتن دستور return، مقدار Void را برمی گرداند که تا حدی صحیح است اما اگر بخواهیم با نگاهی کاملا فنی آن را بررسی کنیم باید بگوییم این تابع never را برمی گرداند! چرا؟ به دلیل اینکه این تابع «هیچ وقت» مقداری برای return کردن نمی سازد. به طور مثال اگر بخواهیم مقدار آن را درون یک متغیر ذخیره کنیم:

function generateError(message: string, code: number) {
  throw { message: message, errorCode: code };
}

const result = generateError('An error occurred!', 500);
console.log(result);

و سپس با tsc app.ts کدها را کامپایل کنم، هیچ چیزی در قسمت کنسول مرورگر نمایش داده نمی شود (به جز خطایی که با throw پرتاب کرده ایم). توجه کنید که هیچ مقداری مثل undefined برگردانده نشده است. تابع generateError هیچ گاه هیچ مقداری تولید نمی کند بنابراین می توان گفت return type این تابع هم void و هم never است.

اگر موس خود را روی generateError ببرید به شما می گوید که تایپ تابع void است چرا که تایپ never کمی جدیدتر است و در نسخه های اصلی زبان تایپ اسکریپت نبوده است بنابراین در اینطور مواقع معمولا همان void برای چنین مقادیری قرار داده می شود مگر اینکه خودتان به صورت دستی آن را روی never تنظیم کنید:

function generateError(message: string, code: number): never {
  throw { message: message, errorCode: code };
}

مثال دیگری از تابعی که از نوع never است حلقه های نامحدود هستند:

while (true) {}

این حلقه همیشه اجرا می شود و هیچ وقت زمانی برای برگرداندن چیزی ندارد بنابراین نوع آن never در TypeScript است.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش جامع تایپ اسکریپت توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مقالات مرتبط
ما را دنبال کنید
اینستاگرام روکسو تلگرام روکسو ایمیل و خبرنامه روکسو