Enum و Type دو ابزار در مدیریت و تعریف دیتا تایپها در برنامههای تایپ اسکریپت هستند و کاربردهای گستردهای دارند، اما هرکدام ویژگیها و کاربردهای خاص خود را دارد. در این مقاله قصد داریم تا به مقایسه این دو ویژگی بپردازیم و تفاوتها، مزایا و محدودیتهای هر کدام از این ویژگیها را بررسی کنیم.
در تایپ اسکریپت، سیستم type به انواع مختلف مقادیری که زبان قبول میکند، اشاره دارد. type، ساختار داده را تعریف میکند و همچنین به ویژگیها و توابع یک مقدار مربوط میشود. این بدان معناست که هر مقدار در تایپ اسکریپت یک type مشخص دارد.
سیستم type قبل از ذخیرهسازی مقادیر در برنامه، آنها را بررسی میکند. این سیستم به ما این امکان را میدهد تا تایپهای دادهای مورد انتظار را برای متغیرها، پارامترهای تابع و مقادیر بازگشتی مشخص کنیم. همین موضوع به شناسایی خطاهای احتمالی در مراحل اولیه توسعه کمک میکند و کیفیت کد را بهبود میبخشد. برخلاف enum که بر روی تخصیص مقادیر خاص تمرکز میکند، type در تایپ اسکریپت بیشتر بر روی تعریف ساختار داده تمرکز دارد.
کامپایلر تایپ اسکریپت از type برای تحلیل کد ما استفاده کرده و خطاها و باگها را پیدا میکند. در تایپ اسکریپت تایپهای مختلفی وجود دارد. برخی از رایجترین آنها عبارتند از:
Enum در تایپ اسکریپت ویژگی خاصی است که به ما اجازه میدهد تا مجموعهای از مقادیر ثابت را تعریف کنیم. این ویژگی معمولاً باعث میشود کدی که داریم خواناتر شود و به ویژه برای نمایش مجموعهای از مقادیر ثابت مانند جهتها، کدهای status یا نقشهای کاربران بسیار مفید میباشد. Enumها راهی برای تخصیص نامهای توصیفیتر به مجموعهای از مقادیر مرتبط ارائه میدهند، که این کار باعث شهودیتر شدن کد ما میشود.
همچنین، Enumها این امکان را به ما میدهند تا مجموعهای از مقادیر مرتبط را که میتوانند عدد یا رشته باشند، بهعنوان مجموعهای از ثابتهای نامگذاری شده، تعریف کنیم. برخلاف برخی از تایپهای موجود در تایپ اسکریپت، Enumها در زمان پیشپردازش پردازش میشوند و در زمان کامپایل یا اجرا تست نمیشوند. برای تعریف Enumها از کلمه کلیدی enum استفاده میکنیم، به این صورت که:
enum Continents { North_America, South_America, Africa, Asia, Europe, Antartica, Australia } // usage var region = Continents.Africa;
Enumها فقط یکی از روشهای مفید برای سازماندهی کد در تایپ اسکریپت هستند. با استفاده از Enum، میتوانیم ثابتهایی ایجاد کنیم که به راحتی میتوانیم با آنها ارتباط برقرار نماییم، و همین موضوع باعث میشود تا ثابتها خواناتر شوند. Enum همچنین به توسعهدهندگان این امکان را میدهد که ثابتهای سفارشی و بهینه از نظر حافظه را در جاوااسکریپت بسازند. همانطور که میدانیم، جاوااسکریپت از Enumها پشتیبانی نمیکند، اما تایپ اسکریپت این قابلیت را در اختیار ما قرار میدهد. در نهایت، Enum در تایپ اسکریپت انعطافپذیری خاصی را ارائه میدهد و این انعطافپذیری باعث میشود موارد مورد نیاز و استفاده خود را به راحتی بیان و مستند کنیم.
ما باید زمانی از تایپهای enum استفاده کنیم که نیاز به نمایش یک مجموعه ثابت از مقادیر داشته باشیم. این بدان معناست که تایپهای enum باید به طور ایدهآل در شرایطی استفاده شوند که مقادیر متمایزی وجود داشته باشد که بتوانیم آنها را بهعنوان ثابت در نظر بگیریم، مانند هفت روز هفته و غیره:
enum Days { Sunday = 1, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }
Enumها میتوانند در داخل مقداردهی آرایهها، مشابه سایر دیتا تایپهای تایپ اسکریپت استفاده شوند. به عنوان مثال:
enum NigerianLanguage { Igbo, Hause, Yoruba } //can be used in array initialisation let citizen = { Name: 'Ugwunna', Age: 75, Language: NigerianLanguage.Igbo }
Enumها همچنین میتوانند در جایی که نیاز به نمایش رشتهها یا ثابتها در یک متغیر باشد، مورد استفاده قرار بگیرند.
Enumها در تایپ اسکریپت میتوانند ابزار مفیدی باشند، اما در برخی شرایط استفاده از آنها غیرضروری است. با این حال، برخی از توسعهدهندگان ممکن است این شرایط را نادیده بگیرند و باز هم از Enumها استفاده کنند، که این کار بهینه نیست؛ Enumها بهترین گزینه برای نمایش یک مجموعه ثابت از مقادیر هستند.
اگر قصد داریم مقادیر اعضای enum را تغییر دهیم یا دوباره تخصیص دهیم، مهم است که به یاد داشته باشیم که Enumها type safe هستند. بنابراین در صورت تغییر مقدار، خطاهای کامپایل را return میکنند. اگر پیشبینی میکنیم که مقادیر باید بهطور داینامیک در زمان اجرا تولید شوند، بهتر است از ثابتها یا ساختارهای دادهای دیگر استفاده کنیم که ممکن است مناسبتر باشند.
مقادیر enum معمولاً از قبل تعریف میشوند، و تعریف و مدیریت یک لیست طولانی از ثابتها در یک enum میتواند طاقتفرسا باشد. به همین دلیل، هنگام کار با مجموعههای بزرگ یا مجموعههای بینهایت از مقادیر، باید از enumها اجتناب کنیم. همچنین، اگر مقادیری که باید نمایش داده شوند از یک دیتا سورس خارجی هستند، استفاده از enum ممکن است انتخاب مناسبی نباشد.
Enumها در تایپ اسکریپت روشی برای تعریف مجموعهای از ثابتهای نامگذاری شده هستند. این قابلیت enum به ما این امکان را میدهد تا بتوانیم در تایپ اسکریپت مجموعهای از مقادیر مرتبط ایجاد کنیم که میتوانند به متغیرها اختصاص داده شوند، یا به عنوان یک type مورد استفاده قرار بگیرند. Enumها روشی راحت برای کار با یک مجموعه ثابت از مقادیر به طور type safe ارائه میدهند. بهطور پیشفرض، enumها مقدار اول را صفر در نظر میگیرند و به هر مقدار بعدی، یک واحد اضافه میکنند. سه نوع مختلف از enumها در تایپ اسکریپت وجود دارد که عبارتند از:
بهطور پیشفرض، Enumها در تایپ اسکریپت بر اساس عدد هستند. این بدان معناست که آنها میتوانند مقادیر رشتهای را به عنوان عدد ذخیره کنند. اعداد و هر تایپ دیگری که با آنها سازگار باشد، میتوانند به یک نمونه از enum اختصاص داده شوند. فرض کنید که میخواهیم روزهای آخر هفته را ذخیره کنیم. Enumهای مربوط به این موضوع در تایپ اسکریپت میتواند چیزی شبیه به مثال زیر باشد:
enum Weekend { Friday, Saturday, Sunday }
در بلاک کد بالا، یک enum به نام Weekend
داریم. این enum سه مقدار دارد: Friday
، Saturday
و Sunday
. در تایپ اسکریپت، مانند دیگر زبانها، مقادیر enum از صفر شروع میشوند و برای هر عضو یک واحد اضافه میشود. آنها به این صورت ذخیره میشوند:
Friday = 0 Saturday = 1 Sunday = 2
ما میبینیم که مقادیر enumها همیشه برای ذخیرهسازی به اعداد اختصاص داده میشوند؛ بهطوری که مقدار اولی همیشه صفر است. ام میتوانیم مقادیر ذخیرهسازی را با منطق خودمان سفارشیسازی کنیم.
در تایپ اسکریپت میتوانیم مقدار عددی اول enumهای خود را مشخص کنیم. با استفاده از مثال روزهای آخر هفته که قبلاً ذکر شد، میتوانیم مقدار عددی اول را به این صورت مقداردهی نماییم:
enum Weekend { Friday = 1, Saturday, Sunday }
بلاک کد بالا، Friday
را به عنوان ۱
، Saturday
را به عنوان ۲
و Sunday
را به عنوان ۳
ذخیره میکند. اگر یک عدد به اولین عضو اضافه کنیم، باز هم سایر اعضا به ترتیب یک عدد افزایش خواهند یافت.
با این حال، ما این قدرت را داریم که مشخص کنیم که نمیخواهیم افزایش ترتیبی داشته باشیم و میتوانیم به هر عضو یک مقدار عددی دلخواه اختصاص بدهیم. بلاک کد زیر semantic است و در تایپ اسکریپت به خوبی کار میکند:
enum Weekend { Friday = 1, Saturday = 13, Sunday = 5 }
مانند سایر دیتا تایپها در تایپ اسکریپت، میتوانیم از enumها بهعنوان پارامترهای تابع یا تایپهای بازگشتی استفاده کنیم، به این صورت که:
enum Weekend { Friday = 1, Saturday, Sunday } function getDate(Day: string): Weekend { if ( Day === 'TGIF') { return Weekend.Friday; } } let DayType: Weekend = getDate('TGIF');
در بالا یک enum به نام Weekend
تعریف کردهایم. سپس یک تابع به نام getDate
تعریف میکنیم که ورودی Day
را میگیرد و یک enum از نوع Weekend
برمیگرداند. در داخل تابع، بر اساس یک شرط، یکی از اعضای enum را return میکنیم.
مقدار یک enum عددی در تایپ اسکریپت میتواند مانند هر دیتا تایپ عددی دیگری، constant یا evaluated باشد. ما میتوانیم enum عددی خود را با یک مقدار محاسباتی تعریف یا مقداردهی کنیم:
enum Weekend { Friday = 1, Saturday = getDate('TGIF'), Sunday = Saturday * 40 } function getDate(day : string): number { if (day === 'TGIF') { return 3; } } Weekend.Saturday; // returns 3 Weekend.Sunday; // returns 120
زمانی که enumها شامل ترکیبی از اعضای محاسبهشده و ثابت باشند، اعضای enum که مقداردهی نشدهاند یا باید اول بیایند یا باید بعد از اعضای دیگر که ثابتهای عددی دارند، قرار بگیرند. اگر این قانون را نادیده بگیریم، با خطای مقداردهی روبهرو خواهیم شد؛ پس باید به یاد داشته باشیم که اگر چنین خطایی رخ داد، اعضای enum را طبق این ترتیب بازچینی نماییم.
اگر میخواهیم عملکرد enumهای عددی خود را بهبود ببخشیم، میتوانیم آنها را به عنوان یک constant تعریف کنیم. برای توضیح این موضوع از مثال روزهای آخر هفته استفاده میکنیم:
enum Weekend { Friday = 1, Saturday, Sunday } var day = Weekend.Saturday;
زمانی که کد به جاوااسکریپت کامپایل میشود، در زمان اجرا، موتور به دنبال Weekend
و سپس Weekend.Saturday
میگردد. برای بهینهسازی عملکرد در زمان اجرا، میتوانیم enum را بهعنوان یک constant تعریف کنیم، مثلا:
const enum Weekend { Friday = 1, Saturday, Sunday } var day = Weekend.Saturday;
کدی که هنگام کامپایل با constant تولید میشود، بهصورت زیر است:
var day = 2;
ما وقتی از const
برای تعریف enum استفاده میکنیم، کامپایلر بهجای اینکه کد اضافی برای تعریف enum تولید کند، بهطور مستقیم از مقادیر استفاده میکند و کدی برای تعریف آن در جاوااسکریپت نمیسازد. مهم است که از این انتخاب و پیامدهایی که ممکن است در هنگام داشتن موارد کاربردی نیازمند جستجوی عدد به رشته یا رشته به عدد پیش بیایند، آگاه باشیم و آن را در نظر بگیریم. همچنین میتوانیم flag کامپایلر preserveConstEnums
را فعال کنیم، در این صورت هنوز هم تعریف Weekend
تولید خواهد شد.
تا اینجا فقط numeric enumها را بررسی کردیم، جایی که مقادیر اعضا، عدد هستند. در تایپ اسکریپت، اعضای enum میتوانند مقادیر رشتهای هم باشند. String enumها برای خوانایی بهتر در زمان گزارش خطا و دیباگ کردن بسیار مهم و آسان هستند، چون مقادیر معنیدار رشتهای دارند. به عنوان مثال:
enum Weekend { Friday = 'FRIDAY', Saturday = 'SATURDAY', Sunday = 'SUNDAY' }
میتوانیم از آن برای مقایسه رشتهها در دستورهای شرطی به این شکل استفاده کنیم:
enum Weekend { Friday = 'FRIDAY', Saturday = 'SATURDAY', Sunday ='SUNDAY' } const value = someString as Weekend; if (value === Weekend.Friday || value === Weekend.Sunday){ console.log('You choose a weekend'); console.log(value); }
در مثال بالا، ما یک string enum به نام Weekend
تعریف کردهایم، درست مانند numeric enum که قبلاً داشتیم، اما این بار مقادیر enum به عنوان string تعریف شدهاند. تفاوت واضح بین numeric enum و string enum این است که مقادیر numeric enum معمولاً به صورت خودکار به ترتیب افزایشی میشوند، در حالی که مقادیر string enum بهطور مستقل مقداردهی میشوند و افزایشی نیستند.
تایپ اسکریپت همچنین امکان ترکیب رشتهها و اعداد را فراهم میکند که به آن heterogeneous enum گفته میشود. در این نوع enum، میتوانیم مقادیر عددی و رشتهای را به اعضای آن اختصاص دهیم. این نوع enum بهندرت استفاده میشود، زیرا کاربردهای محدودی دارد. به عنوان مثال:
enum Weekend { Friday = 'FRIDAY', Saturday = 1, Sunday = 2 }
تایپ اسکریپت از نگاشت دو طرفه پشتیبانی میکند. به این معنی که همانطور که به مقدار یک عضو enum دسترسی داریم، میتوانیم به نام خود enum نیز دسترسی پیدا کنیم. برای نمایش این ویژگی، نمونهای که قبلاً استفاده کردیم را بررسی مینماییم:
enum Weekend { Friday = 1, Saturday, Sunday } Weekend.Saturday Weekend["Saturday"]; Weekend[2];
در بلاک کد بالا، Weekend.Saturday
مقدار ۲
را return میکند، و سپس Weekend["Saturday"]
نیز مقدار ۲
را بازمیگرداند. جالب است که به خاطر نگاشت دو طرفه، Weekend[2]
نام عضو خود یعنی Saturday
را برمیگرداند. ما میتوانیم یک راه ساده برای نمایش نحوهای که تایپ اسکریپت نگاشت دو طرفه را تفسیر میکند، با استفاده از دستور log ببینیم:
enum Weekend { Friday = 1, Saturday, Sunday } console.log(Weekend);
اگر این کد را در کنسول اجرا کنیم، خروجی زیرا را مشاهده خواهیم کرد:
{ '۱': 'Friday', '۲': 'Saturday', '۳': 'Sunday', Friday : 1, Saturday : 2, Sunday : 3 }
این آبجکتها شامل enumها هستند که هم به عنوان مقادیر و هم به عنوان نامها نمایش داده میشوند. این موضوع قدرت نگاشت دو طرفه تایپ اسکریپت را نشان میدهد.
برای extract کردن تایپهای آبجکت از enumها در تایپ اسکریپت، میتوانیم از عملگر keyof
به همراه خود enum استفاده کنیم. به عنوان مثال:
enum Color { Red = 'RED', Green = 'GREEN', Blue = 'BLUE', } type ColorKey = keyof typeof Color; // 'Red' | 'Green' | 'Blue' type ColorValue = typeof Color[ColorKey]; // 'RED' | 'GREEN' | 'BLUE' const colorKey: ColorKey = 'Red'; const colorValue: ColorValue = Color[colorKey]; console.log(colorKey); // Output: 'Red' console.log(colorValue); // Output: 'RED'
در این مثال، عبارت keyof typeof Color
کلیدهای enum Color
را extract میکند: Red
، Green
و Blue
. تایپ نتیجه، ColorKey
است که یک union type از کلیدهای Red
، Green
و Blue
میباشد.
عبارت typeof Color[ColorKey]
با استفاده از کلیدهای extract شده، به مقادیر enum Color
دسترسی پیدا میکند. این کار باعث ایجاد تایپ ColorValue
میشود که یک union type شامل مقادیر RED
، GREEN
و BLUE
است.
سپس میتوانیم از تایپ ColorKey
برای تعریف متغیرهایی که میتوانند کلیدهای enum را نگه دارند، و از تایپ ColorValue
برای تعریف متغیرهایی که میتوانند مقادیر enum را نگه دارند، استفاده کنیم. در مثال بالا، colorKey
به مقدار Red
اختصاص داده میشود که یک کلید معتبر از enum Color
است. بهطور مشابه، colorValue
به مقدار متناظر آن یعنی RED
اختصاص داده میشود. خروجیهای console.log(colorKey)
و console.log(colorValue)
به ترتیب Red
و RED
هستند.
بهطور مستقیم راهی برای تبدیل رشتهها به enum وجود ندارد، زیرا تبدیل یک رشته به enum کار سادهای نیست. با این حال، روشهای مختلفی برای تبدیل رشته به enum وجود دارد و ما دو روش موثر را بررسی خواهیم کرد:
این روش شامل استفاده از یک آبجکت جستجو است که یک نگاشت بین رشتهها و اعضای متناظر enum ایجاد میکند و تبدیل رشته به enum را بهطور ساده و کارآمد ممکن میسازد:
enum Children { First = "Tirenii", Second = "Anita", Third = "Oluwaseun", } const enumLookup: { [key: string]: Children } = { First: Children.First, Second: Children.Second, Third: Children.Third, }; function convertStringToEnum(value: string): Children | undefined { return enumLookup[value]; } console.log(convertStringToEnum("First")); console.log(convertStringToEnum("Second"));
در کد بالا، ما یک enum به نام Children
با مقادیر رشتهای داریم که نمایانگر نام childها هستند. تابع convertStringToEnum
از یک آبجکت جستجو به نام enumLookup
استفاده میکند تا ورودی رشتهای مانند First
را به مقدار متناظر در enum Children
، همانند Children.First
نگاشت کند. این تابع، مقدار متناظر enum را return میکند یا اگر رشته در آبجکت جستجو پیدا نشد، undefined
را برمیگرداند.
نگاشت دو طرفه که پیشتر بررسی کردیم، یک روش مؤثر برای تبدیل رشتهها به enum است. زیرا، با استفاده از آن میتوانیم مقادیر enum را به کلیدهای مربوطهشان تبدیل کنیم:
enum Cars { Honda = 9, Toyota = 6, Kia = 4, } function stringToEnum(value: string): Cars | undefined { const key = Object.keys(Cars).find((key) => key === value); if (key) { return Cars[key as keyof typeof Cars]; } return undefined; } console.log(stringToEnum("Honda")); console.log(stringToEnum("Toyota")); console.log(stringToEnum("Kia"));
در کد بالا، یک enum به نام Cars
تعریف میکنیم که در آن مقادیر عددی به برندهای ماشین اختصاص داده شده است. تابع stringToEnum
از نگاشت دو طرفه استفاده میکند تا نمایش رشتهای یک برند ماشین را به مقدار enum آن تبدیل کند. این تابع از روی کلیدهای enum Cars
عبور میکند، کلید متناظر با رشته ورودی را پیدا کرده و سپس مقدار enum مربوطه را return مینماید. اگر تطابقی پیدا نشد، undefined
را برمیگرداند. اما اگر تطابق پیدا شود، مقدار اختصاص داده شده را return میکند.
برای تبدیل یک numeric enum به آرایه، دو گزینه در تایپ اسکریپت داریم:
Object.values
Object.keys
استفاده از تابع Object.values
به شکل زیر خواهد بود:
num Colors { Red, Blue, Yellow } console.log(Object.values(Color).filter((v) => isNaN(Number(v))) );
برخی موارد وجود دارند که استفاده از enum در آنها بهینه و کارآمد است. همچنین مواردی هم هستند که نباید از enumها استفاده کنیم. در ادامه، بهترین شیوههای استفاده از enumها در تایپ اسکریپت را بررسی خواهیم کرد. این بهترین شیوههای پیشنهادی عبارتند از:
animal
از enum Animal
استفاده کنیم.با پیروی از این بهترین شیوهها، میتوانیم اطمینان حاصل کنیم که enumهای مورد نظر ما در تایپ اسکریپت بهخوبی تعریف شده و قابل نگهداری هستند. همچنین خوانایی کد ما نیز به طور کلی افزایش پیدا میکند.
بسته به نیازی که داریم، گزینههای جایگزینی برای enumها در تایپ اسکریپت وجود دارد که میتوانیم از آنها استفاده کنیم:
as const
: دستور as const
زمانی کاربرد دارد که بخواهیم اطمینان حاصل کنیم که مقادیر یا عبارات به صورت مقادیر غیر قابل تغییر در نظر گرفته شوند و تایپ آنها به تایپ literal خود محدود شود. این کار میتواند type safety بیشتری فراهم کرده و به تایپ اسکریپت کمک کند تا استنتاج تایپ دقیقتری انجام دهد.ما در این مقاله سعی کردیم تا enum و type در تایپ اسکریپت را باهم مقایسه کنیم. همچنین توانستیم نگاه دقیقتری به enum، از جمله انواع و ویژگیهای آنها داشته باشیم. علاوه بر این، نحوه استفاده از آن، از نظر سینتکس و مثالهای عملی را نیز بررسی کردیم. دیگر جنبههای مهم enum مانند مقادیر ثابت در enumها، computed enumها و حتی نگاشت دو طرفه را نیز مشاهده نمودیم.
همچنین، نکتهای که باید به آن توجه داشته باشیم این است که برای string enumها، نگاشت دو طرفه پشتیبانی نمیشود. اما، برای heterogeneous enumها، این قابلیت فقط برای اعضا با تایپ عدد پشتیبانی میشود و برای اعضا با تایپ رشته قابل استفاده نیست.