رویه های مناسب کدنویسی تایپ اسکریپت | راهنمای کاربردی
نوشتن کدهای بهتر تایپ اسکریپت نیازمند درک مقصود این زبان، بازنگری رویکرد کدنویسی، اجتناب از رویهها نامناسب رایج و بهرهگیری از قابلیتهای تایپ اسکریپت است. در این مقاله با روشهای مختلف برای بهبود کدهای تایپ اسکریپت آشنا خواهیم شد و رویه های مناسب کدنویسی تایپ اسکریپت را مرور خواهیم کرد.
ذهنیت تایپ اسکریپت
تایپ اسکریپت، زمانی که به صورت کارآمدی مورد استفاده قرار گیرد، یک زبان قدرتمند محسوب میشود. معنی این حرف آن است که شما باید علیرغم دشواری این کار از ذهنیت جاوا اسکریپت خود را رها کنید و یک ذهنیت تایپ اسکریپتی اتخاذ کنید. به این منظور باید در زمان کدنویسی یک شخصیت متفاوت داشته باشید و روش تفکر خود را در مورد فرایند و روش ابراز خودتان در ساختار کد تغییر دهید. در نتیجهی این تغییر ذهنیت، کد تایپ اسکریپتی که حاصل میشود، بینشهای بهبودیافتهای در مورد فرایند تفکر توسعهدهندگان ارائه میکند.
تایپ اسکریپت به شما امکان میدهد که نیت خود را به روشی روشنتر و دقیقتر تعریف کنید.
اگر دو زبان جاوا اسکریپت و تایپ اسکریپت را دو شخصیت متفاوت تصور کنیم، بهتر میتوانیم درک کنیم که باید کدام خصیصههای شخصیتی را داشته باشیم تا بتوانیم به یک برنامهنویسی کارآمد تایپ اسکریپت تبدیل شویم.
اگر جاوا اسکریپت یک شخص باشد، یک فرد سهلگیر خواهد بود که دست رد به سینه هیچ نوعی نمیزند. همه ما این نوع افراد را میشناسیم. با این دسته از افراد میتوان هر نوع تفریحی را برنامهریزی کرد، اما زمانی که قرار باشد کار جدی انجام دهیم، نباید چندان به آنها تکیه کنید. این افراد در موارد مهم زندگی خرابکاری میکنند. در اغلب برای این که بتوان به این افراد تکیه کرد، باید آنها را قبلاً هدایت و راهنمایی نمود.
این کمک و راهنمایی اضافی از دیدگاه جاوا اسکریپتی به معنی تستهای بیشتر، بررسی نوع و کامنتهای طولانی است. این بررسی و راهنمایی بیشتر چیزی است که تایپ اسکریپت به آن نیازی ندارد.
خصیصههای تایپ اسکریپت
از سوی دیگر اگر بخواهیم تایپ اسکریپت را به افراد تشبیه کنیم، آنها را میتوان مانند اشخاصی تصور کرد که به هیچ کس اعتماد ندارند. این دسته افراد کورکورانه به هیچ چیز اعتماد نمیکنند و بر این تصور نیستند که «انشاءالله مشکلی در ادامه پیش نمیآید». افراد تایپ اسکریپتی میخواهند همه چیز را از قبل بدانند. آنها میخواهند فرایند فکری و نیتهای شما را از قبل بدانند. هیچ گونه تنبلی و اهمالکاری از نظر آنها جایز نیست. تایپ اسکریپت از شما میخواهد که انتظار خود را از کد بگویید تا بتواند به شما کمک کند.
ذهنیت پیشدستانه توسعهدهنده تایپ اسکریپت
تایپ اسکریپت نیازمند یک تغییر در ذهنیت توسعهدهنده به سمت طرز تفکر پیشدستانه، سختگیرانه و اندیشمندانه است.
تایپ اسکریپت قابلیتهایی را در اختیار ما قرار میدهد که موجب میشود بتوانیم ذهنیتی پیشدستانه داشته باشیم. ما این امکان را پیدا میکنیم که کد خود را به صورت صریح حاشیهنویسی و اطلاعات مورد نیاز برای نوعبندی استاتیک را عرضه کنیم و در نتیجه تجربه توسعه بهبود مییابد. تایپ اسکریپت به ما امکان میدهد که به سطحی از تحلیل استاتیک کد دست پیدا کنیم که امکان دستیابی به آن در جاوا اسکریپت دشوار بوده است. بدین ترتیب میتوانیم باگها را پیش از آن که حتی رخ بدهند کشف کنیم.
جاوا اسکریپت بیش از حد بخشنده است، اما تایپ اسکریپت تلاش میکند این وضعیت را عوض کند.
بایدها و نبایدهای تایپ اسکریپت
مواردی که در این بخش مطرح میشوند، اختصاص به تایپ اسکریپت دارند و هردوی تایپ اسکریپت و جاوا اسکریپت را شامل نمیشوند. بین همه این بایدها و نبایدها یک مفهوم مشترک وجود دارد و آن این است که رفتار نامطلوب تایپ اسکریپت از میل به کدنویسی با آن همانند جاوا اسکریپت ناشی میشود.
با این که ممکن است در صورت داشتن تجربه بلندمدت کدنویسی با جاوا اسکریپت، در زمان ابتدای سوئیچ به تایپ اسکریپت با کاهش بهرهوری مواجه شوید، اما زمانی که در این زبان تسلط پیدا کنید، بهرهوری و علاوه بر آن کیفیت و خوانایی کد شما به سطحی فراتر از کد جاوا اسکریپت میرسد.
از این رو با این که به نظر میرسد با دور زدن تایپ اسکریپت و عدم استفاده از نوعبندی، در زمان خود صرفهجویی میکنید، اما این در کوتاه مدت است و عواقب منفی بلند مدت چسبیدن به رفتار جاوا اسکریپتی بر این مزیتهای کوتاه مدت خواهد چربید.
این عواقب به شکل باگهای ردیابی نشده، خوانایی پایین و کدبیس با حجم بالاتر خود را نشان میدهند. این یک واقعیت است که شما امروز ناگزیر از یادگیری تایپ اسکریپت هستید و از این رو هر چه سریعتر این کار را انجام دهید، بهتر است. این واقعیت را نیز فراموش نکنید که تایپ اسکریپت برای حل مشکلات جاوا اسکریپت ساخته شده است. در ادامه برخی نکات و ترفندهای کدنویسی کارآمد در تایپ اسکریپت را با هم مرور میکنیم.
استفاده از Strict Mode
همواره از Strict Mode استفاده کنید. این کار به سادگی تعیین مشخصه strict: true در گزینه کامپایلر در فایل tsconfig.json است. این حالت به صورت پیشفرض غیر فعال است. حالت Strict امکان اعتبارسنجی بهبودیافته را با نوعبندی سختگیرانهتر فراهم میسازد. به این ترتیب تضمین محکمتری در مورد نوعبندی در کد ایجاد میشود. تعیین حالت Strict روی مقدار True ما را قادر میسازد که همه قابلیتهای متعلق به خانواده Strict را فعال کنیم سپس میتوانید گزینهها را به صورت یک به یک بسته به نیاز غیر فعال کنید. حالت strict طیف وسیعی از رفتار بررسی نوع را فراهم میسازد.
خانواده Strict و گزینههای حالت Strict
برخی گزینههای مهم در زمان تعیین strict: true به عنوان بخشی از خانواده strict فعال میشوند. این موارد شامل فهرست زیر هستند:
- strictNullChecks – زمانی که این گزینه مقدار false داشته باشد، مقادیر null و undefined از سوی کامپایلر تایپ اسکریپت نادیده گرفته میشود. معنی این حرف آن است که میتوانید هر مقدار null یا undefined را انتساب دهید و نگران دخالت تایپ اسکریپت نباشید. به این ترتیب هیچ تضمینی نیست که متغیر مقدار null یا undefined بگیرد و در اغلب موارد موجب بروز خطاهای غیر قابل ردگیری میشود.
تعیین strictNullChecks به صورت true به کامپایلر دستور میدهد که به انتساب مقادیر null و undefined حساسیت نشان دهد. یعنی شما باید صریحاً تعریف کنید که یک متغیر میتواند مقادیر null یا undefined بگیرد. به این ترتیب از null شدن ناخواسته مقادیر جلوگیری میشود.
- noImplicitAny – زمانی که این گزینه مقدار true داشته باشد، باید همه انواع متغیرها، تابعها، پارامترها و غیره را اعلان کنید. به این ترتیب دیگر در دامن تابعهای شبیه جاوا اسکریپت یعنی تعریف تابع بدون نوع نمیافتیم.
از این رو تعریف زیر موجب بروز یک خطا میشود:
const func = (param) => 'param is ' + param
در حالی که تعریف زیر از نظر تایپ اسکریپت، معتبر است:
const func = (param: string) => 'param is ' + param
چرا باید از حالت Strict استفاده کنیم؟
شناسایی مشکلات در چرخه عمر توسعه نرمافزار هر چه قدر سریعتر اتفاق بیفتد، همان قدر کم هزینهتر است. در ابتدا بسته به کیفیت/حالت کد ممکن است از دیدن حجم خطاهایی که در کد وجود دارد، شگفتزده شوید. اما به خاطر داشته باشید که تایپ اسکریپت انتظار دارد که حواستان بیشتر از جاوا اسکریپت جمع باشد. هدف تایپ اسکریپت این است که شما اپلیکیشنهایی با کدهایی با کیفیت بالا و نوعبندی قویتر و باگهای کمتر بسازید.
حالت Strict آسانترین مسیر به سوی سازگاری با سیستم نوعبندی تایپ اسکریپت محسوب میشود. با استفاده از این حالت یک بینش هوشمندانه در اختیار ما قرار میگیرد که کمک میکند تا روابط وجود در کد را بهتر درک کنیم و همچنین روابط بین کامپوننتهای فراوان کوچک، سیستمها و سرویسهایی که پروژه ما به آنها تقسیم شدهاند و با همدیگر تعامل دارند را به نحو درستی بفهمیم.
در چه مواردی نباید از حالت Strict استفاده کنیم؟
ممکن است وسوسه شوید تا در ابتدا حالت Strict را روی false تنظیم کنید. مهاجرت روی پروژههای کنونی به تایپ اسکریپت شرایطی است که باید حالت Strict را در ابتدا غیر فعال کنید تا این جابجایی به شکل روانتری انجام یابد. در مورد پروژههای جدید هیچ دلیل منطقی برای عدم استفاده از حالت Strict وجود ندارد. استفاده از حالت Strict از همان آغاز پروژه روشی برای ساخت اپلیکیشنهای کارآمد است که قابل اعتماد هستند.
هر چه سریعتر با حالت Strict سازگار شوید، از عادتهایی که به تازگی آموختهاید، سریعتر منتفع خواهید شد.
نوعها را سرکوب نکنید
سرکوب کردن نوعها در تایپ اسکریپت موجب میشود که همان کد جاوا اسکریپت را با طولی بیشتر به دست آورید. بدین ترتیب دیگر این نه کد جاوا اسکریپت و نه تایپ اسکریپت نخواهد بود.
سوءاستفاده از Any
یکی از رایجترین روشها برای سرکوب کردن نوعبندی تایپ اسکریپت، تبدل نوع به Any است. برخی اوقات وسوسه میشویم که کامپایلر را از این طریق خاموش کنیم. به خصوص در حالتی که زمان تنگ باشد و کاملاً مطمئن باشید که چه کاری انجام میدهید این وضعیت بیشتر پیش میآید.
با این حال، همواره بهتر است که با علت و نه نشانه برخورد کنید. بنابراین شاید بهتر باشد که اجازه دهید تایپ اسکریپت خطاها را نمایش دهد و متوجه اشتباهاتتان در کدنویسی بشوید. سرکوب کردن نوعبندی موجب میشود این حس تصور ایجاد شود که یکی از دو اتفاق زیر افتاده است. یا توسعهدهنده به انجام دادن کار بیش از شیوه انجام دادن آن اهمیت داده است و یا این که تا زمانی که کامپایلر ابراز خطا نکرده است اقدام به تعیین نوع نکرده است.
به این ترتیب یک چرخه بیپایان سرکوب نوع، سپس، خطا، سپس، سرکوب نوع، سپس خطا ایجاد میشود.
خطر تبدیل نوع به Any
با تبدیل متغیرها به نوع any به صورت زیر به transpiler اعلام میکنید که این متغیر هر چیزی را قبول میکند.
(obj as any).getName()
به این ترتیب میتوانید هر تغییری را فراخوانی کرده و آن را به هر نوعی انتساب دهید. در واقع به این ترتیب اعلام عمومی میکنید که این متغیر میتواند هر چیزی باشد. این وضعیت هیچ تضمینی ایجاد نمیکند که کد از کار نخواهد افتاد.
به علاوه استفاده از نوع any در چند محل مختلف در کد به آن معنی است که همه خطاهای مرتبط با نوع را روی حجم بزرگی از کد سرکوب خواهید کرد. به این ترتیب کامپایلر تایپ اسکریپت سختتر کار میکند و تست کردن دشوارتر میشود، خوانایی کاهش مییابد و در نتیجه باگهایی پدید میآیند که رفعشان زمانگیر است و هرکسی از آنها نفرت دارد.
اگر نوع را نمیدانید و یا نمیتوانید ایجاد کنید، از unknown استفاده کنید
هر چیزی به unknown قابل انتساب است، اما unknown به هیچ چیزی به جز خودش قابل انتساب نیست و به این منظور به type assertion نیاز است.
این بدان معنی است که فراخوانی متدها روی متغیر از نوع unknown موجب بروز یک خطا خواهد شد که چیز خوبی محسوب میشود. از آنجا که ما نمیخواهیم یک متد را فراخوانی کنیم که نمیتوانیم وجود آن را تضمین کنیم، گردش اپلیکیشن خراب شده و تجربه کاربری متأثر میشود.
انواع را به طرز درستی تعریف کنید تا این وضعیت پیش نیاید
اگر انواع را در زمان نوشتن کد تایپ اسکریپت به درستی تعریف نکنید، در موقعیتی قرار میگیرید که:
- خطاهای زیادی ایجاد میشوند.
- درک میکنید که باید به عقب بازگردید و کد تایپ اسکریپت را از همان ابتدای کار با نوعهای صحیح بنویسید.
- در برابر این موقعیت مقاومت میکنید، زیرا هیچ کس دوست ندارد کاری را که زمان زیادی برای آن صرف کرده، مورد بازنویسی قرار دهد.
- بنابراین ممکن است کد به مراتب بدتری بنویسید.
- این چرخه تکرار میشود.
شما باید از قرار گرفتن در این موقعیت، خودداری کنید.
گاردهای نوع را نادیده نگیرید
نوعبندی دینامیک موجب میشود که تشخیص یک شیء که نوع خاصی دارد، دشوار شود. در زمان استفاده از اینترفیسها در تایپ اسکریپت در اغلب موارد باید بررسی کنید که یک شیء کدام اینترفیس را پیادهسازی کرده است. با این حال امکان بررسی برابری نوع برای اینترفیسها بدون مقایسه مشخصههای متمایزکننده زیرساختی میسر نیست.
کاربرد گارد داخلی typeof
گارد typeof تنها برای بررسی نوعهای string ،number ،bigint ،function ،boolean ،symbol ،object و undefined استفاده میشود. از این رو، بررسی برابری نوع سفارشی خارج از دامنه عملگر typeof است. عملگر typeof تنها یک بررسی نوع سطحی ارائه میکند.
بررسی نوع با استفاده از typeof برای استفاده روی انواع سفارشی بیش از حد سادهسازی شده است.
کاربرد گارد داخلی instanceof
گارد instanceof تنها زمانی ارزشمند است که بخواهیم نوع کلاسها را بررسی کنیم. این گارد بررسی میکند که آیا یک شیء وهلهای از یک کلاس است یا نه و هیچ ربطی به اینترفیسها ندارد.
در نتیجه گارد instanceof میتواند منجر به نتایج منفی نادرستی شود. یعنی در برخی موارد حتی در صورتی که شکل زیرساختی شیء یکسان باشد، مقدار false بازگشت میدهد. بنابراین استفاده از instanceof روی اینترفیسها ممکن نیست.
استفاده از گاردهای نوع سفارشی تایپ اسکریپت
نوشتن گاردهای سفارشی نوع تایپ اسکریپت یک روش با قابلیت استفاده مجدد برای بررسی نوعهای اینترفیس پیش از تعامل یافتن با یک شیء فراهم میسازد. یک گارد نوع اساساً تابعی است که یک مقدار boolean بازگشت میدهد.
شما باید یک شیء را ارسال کنید تا به عنوان یک پارامتر در تابع گارد مورد بررسی قرار گیرد.
1function isPerson(user: Person | Dog) user is Person {
2return user.discriminator === 'person';
3}
قدرت ژنریکها را نادیده نگیرید
ژنریکها در زمینه نوشتن کد با مقیاسپذیری که بتواند در سراسر پروژه مورد استفاده مجدد قرار گیرد نقشی کلیدی دارند. ژنریکها یک قابلیت کلیدی تایپ اسکریپت هستند که مقیاسپذیری کد را افزایش میدهند.
نوشتن کد ژنریک نیازمند استفاده از پارامترهای ژنریک از قبیل filter<T>(param: T[]): T[] است که در آن T یک نوع ژنریک است که به تعریف یک تابع مانند filter<User[]>(users) و filter<Post[]>(post) ارسال میشود و به کامپایلر امکان میدهد که همه کاربردهای آن نوع را در بدنه تابع تأمین کند.
ژنریک را میتوان به عنوان یک placeholder برای یک نوع دینامیک تصور کرد.
برای این که مطمئن شویم کی تابع به عنوان تابع ژنریک عمل میکند. این تابع باید یک مسئولیت منفرد داشته باشد و بتواند ورودیهای متنوع را مدیریت کند.
کارکردهای ژنریکها
- ژنریکها مفاهیم DRY را ارتقا میبخشند.
- مقدار کد مورد نیاز برای نوشتن را کاهش میدهند.
- تضمین نوع را در تابعهای چندریختی ایجاد میکنند.
ژنریکها در نهایت موجب کاهش هزینههای توسعه میشوند، زیرا روی رفتار برنامهنویسی تأثیر دارند. نخستین کارکرد آنها صرفهجویی در هزینه و زمان مورد نیاز برای کدنویسی است، چون در زمان استفاده از ژنریکها دیگر نیازی نیست که چرخ را از نو اختراع کنید.
نکته دوم این است که ژنریکها کدبیس تمیزی ایجاد میکنند و حجم تابعها، کلاسها و کامپوننتها را کاهش میدهند. بدین ترتیب یک محیط آسانتر برای توسعه تیمی و درک و استفاده از کدهای همکاران ایجاد میشود.
در نهایت ژنریکها ما را از استفاده از نوع any بازمیدارند. این امر در زمان نوشتن کدهای جاوا اسکریپت که قابلیت استفاده مجدد داشته باشند، ناگزیر است. بدین ترتیب کدبیس پایدارتری ایجاد میشود که باگهای کمتری به جهت خطاهای مرتبط با نوع دارد، چون بررسیهای نوع قویتری اجرا میشود که در زمان کامپایل در اختیار ما قرار گرفتهاند.
سخن پایانی
استفاده از عادتها و رویههای برنامهنویسی جاوا اسکریپت در محیط تایپ اسکریپت موجب میشود که این زبان ماهیت و مفهوم خود را از دست بدهد در صورتی که با اتخاذ رویههای تایپ اسکریپت کاری کنید که کامپایلر تایپ اسکریپت از شما راضی باشید، پادش آن را در ادامه با داشتن یک کدبیس منسجم و تمیز به دست میآورید.