ویرگول
ورودثبت نام
مهدی فلاحتی
مهدی فلاحتی
مهدی فلاحتی
مهدی فلاحتی
خواندن ۶ دقیقه·۱ ماه پیش

چرا باید از ESLint استفاده کنیم و چندتا rule مهم

استفاده از ESLint توی پروژه‌های جاوااسکریپتی، مخصوصاً پروژه‌های تیمی، عملاً به یه استاندارد تبدیل شده.

از اونجایی که میدونید جاوااسکریپت خیلی ساختار خاصی نداره و کلا با همه چی اوکی هست 😅

هدف این بوده که اگه یه تیکه کد توی یه صفحه وب مشکل داشت، کل صفحه سفید نشه یا کرش نکنه و کاربر بتونه همچنان با سایت کار کنه. برای همین مثلاً اگه عدد رو با رشته جمع کنید، به جای اینکه مثل زبان‌های C# یا Java همون اول خطا بده، سعی می‌کنه خودش یه جوری تبدیلش کنه (Type Coercion) و ادامه بده. اما همین مورد باعث شد جاوااسکریپت، توی پروژه‌های بزرگ تبدیل به منبع اصلی باگ‌های عجیب و غریب بشه 😁»


مثلا فرض کنید خواستید یه عدد رو با یه رشته جمع کنید؛ اگه قرار بود جاوااسکریپت همون
خط اول خطا بده، کل سایت بالا نمیومد 😁

TypeScript جلوی بخش زیادی از خطاهای مربوط به نوع داده رو می‌گیره، اما ESLint همچنان برای enforce کردن الگوهای درست و جلوگیری از اشتباهات منطقی نیازه.


تو این پست قصد ندارم در مورد نصب و این موارد صحبت کنم چون به صورت پیش فرض معمولا موقع نصب react و یا next ، پکیج های مرتبط به lint هم نصب میشه.


۱- no-implicit-coercion و prefer-template

این دو Rule جزو مهم‌ترین مواردی هستن که جلوی خیلی از باگ‌های ریز و درشت، مخصوصاً در کار با رشته‌ها و تبدیل نوع‌ها رو می‌گیرن.

no-implicit-coercion اجازه نمی‌ده که با عملیات عجیب‌وغریب، نوع داده‌ها رو به‌صورت غیرمستقیم عوض کنیم.
prefer-template هم ما رو مجبور می‌کنه به‌جای استفاده از + برای ساخت رشته، از Template Literal استفاده کنیم.

// ❌ استفاده از + برای ترکیب رشته‌ها const firstName = "mahdi"; const lastName = "falahati"; const fullName = firstName + " " + lastName; // هر دو رشته هستند const greeting = "سلام " + firstName; // هر دو رشته هستند // ✅ روش بهتر: const fullName = `${firstName} ${lastName}`; const greeting = `سلام ${firstName}`; // ❌تبدیل به رشته const age = 25; const ageString = age + ""; // ❌ تبدیل عدد به رشته const ageString = "" + age; // ❌ تبدیل عدد به رشته // ✅ تبدیل صریح const ageString = String(age); // ✅ واضح و خوانا const ageString = age.toString(); // ✅ یا این روش // ❌ ترکیب عدد و رشته const userId = 123; const message = "User ID: " + userId + ""; // "" اضافی و بی‌معنی // ✅ const userId = 123; const message2 = `User ID: ${userId}`; // روش بهتر

'no-implicit-coercion': ['error', { boolean: true, // Disallow !!value number: true, // Disallow +value or value * 1 string: true, // Disallow value + "" disallowTemplateShorthand: false // Allow ${value} for string coercion }], "prefer-template": "error"



۲- Code Formatting Rules (بهتر است به Prettier سپرده شود)

یکی از مهم‌ترین چالش‌ها در کار تیمی، یکدست بودن فرمت کدهاست.
اگر هر توسعه‌دهنده به کد فرمت خودش بنویسه، نتیجه میشه Diffهای شلوغ، Code Review سخت و کاهش خوانایی کد.

"rules": { "object-curly-spacing": ["error", "always"], "key-spacing": ["error", { "afterColon": true }], "keyword-spacing": ["error", { "before": true, "after": true }] }

یک سری rule هایی هست برای code formatting ولی بهتره این مورد بسپاریم به prettier.
معمولاً با کمک eslint-config-prettier تمام قوانین فرمت‌بندی ESLint غیرفعال می‌شوند تا از تداخل بین این دو ابزار جلوگیری شود.

برای مثال، قوانینی مانند فاصله بین کلید و مقدار آبجکت‌ها یا فاصله قبل و بعد از کلمات کلیدی (if، else، try و …) به‌صورت کامل توسط Prettier مدیریت می‌شوند و نیازی به تعریف آن‌ها در ESLint نیست.

در مورد محدودیت طول خطوط (max-len) نیز معمولاً پیشنهاد می‌شود به‌جای استفاده از ESLint، از تنظیم printWidth در Prettier استفاده شود. با این کار، شکستن خطوط به‌شکل هوشمند و یکنواخت انجام می‌شود و از ایجاد اختلاف بین ابزارها و ادیتورهای مختلف جلوگیری خواهد شد.

"rules": { "max-len": ["error", { "code": 100, "ignoreUrls": true, "ignoreStrings": true, "ignoreTemplateLiterals": true, "ignoreRegExpLiterals": true }] }

با استفاده از این rule میتونیم تعداد کاراکترهای مجاز در هر خط محدود کنیم ولی همون طور که گفته شد بهتره این موارد بسپاریم به Prettier

نتیجه نهایی برای این بخش : ترکیب صحیح Prettier برای فرمت کد و ESLint برای بررسی کیفیت و منطق کد باعث می‌شه:

  • کدهای تیم یکدست باشند

  • Diff فایل‌ها در Git تمیزتر و خواناتر شوند

  • Code Review ساده تر باشه

  • اختلافی بین خروجی VS Code، WebStorm و... وجود نداشته باشه

۳- Logic & Best Practices Rules

در بخش قبلی در مورد چند rule برای یکدست شدن کدها صحبت کردیم، در این قسمت چندتا rule مهم برای تمیزتر شدن کدها و همچنین باگ کمتری پیش بیاد.

اولین مورد eqeqeq هست.

// ❌ باگ‌های عجیب ناشی از استفاده از == if (0 == false) { console.log("چرا اجرا شدی؟!"); } if ("1" == 1) { // اینم اجرا میشه چون رشته "1" تبدیل به عدد میشه 😐 } // ✅ روش درست با === if (0 === false) { // اجرا نمیشه، چون عدد 0 با بولین false یکی نیست }

== معمولاً به‌خاطر تغییر خودکار نوع‌ها نتیجه‌های عجیب می‌ده، برای همین حتما باید از === استفاده بشه.

TypeScript هم تا حد زیادی جلوی این اشتباه‌ها رو می‌گیره، ولی اساسا جلوی اینکه == استفاده کنیم نمیگیره یه مثال که تایپ اسکریپت جلوش نمیگیره.

const value = 'test' as unknown as number; if (value == 5) {}

اینجا TS فکر می‌کنه value یه عدد هست، ولی در زمان اجرا همچنان یه رشته‌ست و == می‌تونه رفتار غیرمنتظره ایجاد کنه.
هرچند احتمال داشتن چنین cast‌ هایی کم به‌نظر می‌رسه، ولی خب… در جاوااسکریپت هیچ‌چیزی بعید نیست 😅


مورد بعدی no console هست

به نظرم rule مهمی هست خیلی وقت ها احتمالش وجود داره که یک console log گذاشته باشیم و فراموش شده باشه پاکش کنیم چه‌بسا که یک سری اطلاعات مهم هم داخلش باشه 🥲

"no-console": ["error", { "allow": ["warn", "error"] }]

البته بعضی موارد پیش میاد که نیاز هست یک console warn یا error استفاده کنیم با این روش میتونیم اجازه استفاده بدیم.


و مورد آخر no-unused-vars

خیلی وقت‌ها پیش میاد یک متغیر یا یک تابع تعریف کنیم اما فراموش کنیم ازش استفاده کنیم، یا موقع Refactor کردن دیگه لازمش نداریم و همون‌طور توی کد بمونه.

برای همینESLintبا این Rule جلوش رو می‌گیره:

"no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }]

به این شکل:

  • هر متغیر، تابع یا importی که استفاده نشه → خطا ❌

  • روی آرگومان‌های تابع سخت‌گیر نیست (برای جلوگیری از خطاهای الکی)

  • در destructuring هم باعث مزاحمت نمی‌شه

✔️ مثال برای args: "none"

// مثال رایج در map items.map((item, index) => { return item.name; //index is not used, but with args: "none" it's not a problem });

✔️ مثال برای ignoreRestSiblings: true

وقتی از Rest استفاده می‌کنیم تا بقیه پراپرتی‌ها رو جدا کنیم، اما اون متغیرهای اولیه (Siblingها) رو لازم نداریم و بلااستفاده می‌مونن.» (چون در واقع ما از Rest استفاده می‌کنیم، ولی از اون متغیرهایی که جدا کردیم مثل password استفاده نمی‌کنیم).


بدون این تنظیم خطا می‌داد، با این تنظیم خطا نمیده.

const user = { name: "mahdi", age: 25, password: "12345" }; const { password, ...safeUser } = user; console.log(safeUser);

این کار کمک می‌کنه کد تمیزتر، قابل‌خواندن‌تر و بدون بخش‌های مرده باشه.




در نهایت، بد نیست بدونیم استفاده از ESLint همیشه هم بدون دردسر نیست.
گاهی یه خط ساده می‌نویسی و پنج‌تا خطا تحویل می‌گیری، یا سر یه Rule خاص کلاً کُپ می‌کنی که چرا الان گیر داده 😅
بعضی وقت‌ها هم مثل عکس پایین، کار به جایی می‌رسه که به این فکر میفتی که ولش کن اصلا نخواستیم کلا غیرفعالش میکنیم میره 😁
"wtf is wrong with eslint?!" 😂

اما واقعیت اینه که همین سخت‌گیری‌هاست که باعث میشه کد تمیزتر، و قابل‌نگه‌داری‌تری داشته باشیم.

امیدوارم این متن براتون مفید بوده باشه ❤️
اگر نظری داشتید یا تجربه‌ای با ESLint دارید و یا چیزی اشتباه گفتم ممنون میشم بهم تو نظرات بگید 🙏

code revieweslintreacttypescriptnextjs
۱
۰
مهدی فلاحتی
مهدی فلاحتی
شاید از این پست‌ها خوشتان بیاید