اگر توسعه دهنده ای هستید که با TypeScript آشنا هستید، می دانید که این زبان چقدر قدرتمند و انعطاف پذیر است. TypeScript تایپ ایستا و تجزیه و تحلیل کد قوی را ارائه می دهد و به کشف خطاها در مراحل اولیه توسعه کمک می کند. یکی از ویژگی های کلیدی TypeScript توانایی آن در کار با انواع مختلف داده است. در این مقاله، به دنیای فیلتر کردن انواع مختلف مقادیر در TypeScript خواهیم پرداخت. ما تکنیکهای مختلف فیلتر را بررسی میکنیم و مثالهای عملی برای تقویت درک شما ارائه میکنیم.
در این آموزش، آرایهای حاوی دادههای انواع mixed را با استفاده از متد ()filter
فیلتر میکنیم و مطمئن میشویم که TypeScript مقادیر را به درستی استنتاج میکند.
پیش نیازها
برای دنبال کردن این آموزش، شما نیاز دارید:
1.TypeScript روی سیستم شما راه اندازی شده است
2.برای یادگیری نحوه تنظیم آن، به صفحه مستندات مراجعه کنید. اگر نمیتوانید آن را تنظیم کنید یا نمیخواهید، میتوانید از زمین بازی TypeScript استفاده کنید
3.آشنایی با رابط ها و تایپ گارد در TypeScript
4.یک ویرایشگر متن خوب که می تواند خطاها را قبل از کامپایل به شما نشان دهد، مانند VS Code، که دارای پشتیبانی داخلی TypeScript است.
نحوه فیلتر کردن عناصر در TypeScript
یکی از رایج ترین وظایف در برنامه نویسی فیلتر کردن یک آرایه است. جاوا اسکریپت با متد ()filter
ارائه می شود که یک آرایه را بر اساس معیارها یا شرایط داده شده فیلتر می کند و یک آرایه جدید را تنها با عناصری که شرط داده شده را پاس کرده اند برمی گرداند.
با فرض اینکه یک آرایه با اعداد دارید:
const numbers = [10, 18, 20, 30, 40];
اگر می خواهید یک آرایه جدید فقط با اعداد بزرگتر از 20 ایجاد کنید، می توانید عناصر را به صورت زیر فیلتر کنید:
onst greaterThanTwenty = numbers.filter((number) => {
return number > 20;
});
console.log(greaterThanTwenty);
// output
[30, 40]
متد ()filter
یک callback
می گیرد که بررسی می کند که آیا عددی بزرگتر از 20 است یا خیر، و اگر شرط برآورده شود، مقدار true
را برمی گرداند. سپس متد آرایهای را برمیگرداند که فقط شامل عناصری است که شرط را برآورده میکنند.
TypeScript می تواند نوع آرایه جدیدی را که توسط متد ()filter
برگردانده شده است، زمانی که روی متغیر greaterThanTwenty
در ویرایشگر خود نگه دارید یا از زمین بازی TypeScript استفاده می کنید، می توانید تایپ آن را ببینید.
در زیر مثال دیگری است که داده های پیچیده را مدیریت می کند. در آن، ما یک رابط Doctor را برای نمایش اشیایی که در آرایه Doctor
هستند تعریف می کنیم. سپس از متد ()filter
برای برگرداندن آبجکت هایی استفاده می کنیم که دارای یک ویژگی خاص هستند که به Cardiology
تنظیم شده است:
interface Doctor {
type: "DOCTOR";
name: string;
specialty: string;
}
const doctors: Doctor[] = [
{ type: "DOCTOR", name: "John Doe", specialty: "Dermatology" },
{ type: "DOCTOR", name: "Jane Williams", specialty: "Cardiology" },
];
const cardiologists = doctors.filter(
(doctor) => doctor.specialty == "Cardiology"
);
هنگامی که ماوس را روی متغیر Cardiology
میچرخانیم، متوجه میشویم که TypeScript استنباط میکند که آرایه حاوی آبجکت هایی است که با رابط Doctor مطابقت دارند.
همانطور که دیدیم، TypeScript هنگام استفاده از متد ()filter
بدون هیچ مشکلی میتواند انواع را استنباط کند - زیرا آرایههایی که تا کنون به آنها نگاه کردهایم حاوی عناصری از یک نوع هستند. در بخش بعدی به فیلتر کردن یک آرایه با عناصر مختلف خواهیم پرداخت.
فیلتر کردن آرایه ای از انواع عناصر مختلف در TypeScript
در این بخش، یک برنامه کوچک ایجاد می کنیم که حاوی آرایه ای از عناصر از انواع مختلف است تا مشکلاتی را که در طول استنتاج TypeScript ایجاد می شود، مشاهده کنیم.
برای شروع، دو رابط ایجاد کنید، Doctor
و Nurse
:
interface Doctor {
type: "DOCTOR";
name: string;
specialty: string;
}
interface Nurse {
type: "NURSE";
name: string;
nursingLicenseNumber: string;
}
type MedicalStaff = Doctor | Nurse;
در مثال، شما دو واسط Docto
r و Nurse
را برای نمایش اشیایی که در آرایه ای که به زودی تعریف خواهیم کرد، تعریف می کنید. رابط Doctor
یک شی را با فیلدهای نوع، نام و تخصص نشان می دهد. رابط پرستار دارای فیلدهای نوع، نام و NursingLicenseNumber
است.
برای ذخیره اشیایی که می توانند با رابط دکتر یا پرستار نمایش داده شوند، در خط آخر یک MedicalStaff
از نوع union تعریف می کنیم.
سپس، یک آرایه حاوی اشیایی ایجاد کنید که با نوع union MedicalStaff
مطابقت دارند:
...
const doctor1: MedicalStaff = {
type: "DOCTOR",
name: "John Doe",
specialty: "Dermatology",
};
const doctor2: MedicalStaff = {
type: "DOCTOR",
name: "Jane Williams",
specialty: "Cardiology",
};
const nurse1: MedicalStaff = {
type: "NURSE",
name: "Bob Smith",
nursingLicenseNumber: "RN123456",
};
ما یک آرایه staffMembers
ایجاد کردیم که شامل چهار شیء است. دو شیء اول با رابط دکتر و دو شیء دیگر با رابط پرستار نشان داده می شوند.
به دنبال این، اشیایی را که دارای ویژگی nursingLicenseNumber
نیستند، فیلتر کنید:
...
const nurses = staffMembers.filter((staff) => "nursingLicenseNumber" in staff);
const nursingLicenseNumbers = nurses.map((nurse) => nurse.nursingLicenseNumber);
console.log(nursingLicenseNumbers);
در خط اول، تمام اشیایی را که دارای ویژگی nursingLicenseNumber
نیستند، که اشیاء مربوط به رابط Doctor هستند، فیلتر می کنیم. در مرحله بعد، از متد ()map
استفاده می کنیم تا فقط اعداد مجوز پرستاری را در متغیر nursingLicenseNumbers
برگردانیم. سپس شما یک هشدار می بینید.
پس از بررسی دقیق، هشدار مشابه موارد زیر است:
// Error
Property 'nursingLicenseNumber' does not exist on type 'Doctor | Nurse'.
Property 'nursingLicenseNumber' does not exist on type 'Doctor'.
این به این دلیل است که نوع استنباط شده برای متغیر nurses
در []const nurses (Doctor | Nurse)
است: حتی اگر متد ()filter
اشیاء را بدون nursingLicenseProperty
حذف کند. بدتر از آن، اگر ماوس را روی ویژگی nursingLicenseNumbers
نگه دارید، TypeScript آن را به عنوان []const nursingLicenseNumbers : any
استنتاج می کند.
در موارد ایدهآل، متغیر nurses
باید به عنوان []const nurses: Nurse
. به این ترتیب، TypeScript در map()
nurse.nursingLicenseNumber
را علامت گذاری نمی کند.
فیلتر کردن با استفاده از guard نوع سفارشی با گزاره نوع
تا کنون، ما یاد گرفتهایم که TypeScript flags nurse.nursingLicenseNumber
را نشان میدهد زیرا این ویژگی در رابط Doctor
در دسترس نیست. برای دور زدن این خطا، باید از guard نوع سفارشی با گزاره نوع استفاده کنیم.
یک guard نوع سفارشی میتواند تقریباً هر نوع guardی را که خودمان تعریف میکنیم، در مقایسه با guard های نوع دیگر، مانند typeof
، که به چند نوع داخلی محدود میشوند، بررسی کند.
در مثال ما، یک نوع گزاره از staff is Nurse
به متد ()filter
به عنوان annotation نوع بازگشت صریح اضافه کنید:
const nurses = staffMembers.filter(
(staff): staff is Nurse => "nursingLicenseNumber" in staff
);
const nursingLicenseNumbers = nurses.map((nurse) => nurse.nursingLicenseNumber);
console.log(nursingLicenseNumbers);
تایپ پردیکت staff is Nurse
به TypeScript می گوید که تابع ارسال شده به متد ()filter
از نوع Nurse
خواهد بود.
اگر اکنون ماوس را روی متغیر nurses
نگه دارید، TypeScript آن را به صورت []Nurse:
استنباط می کند:
const nurses: Nurse[] = staffMembers.filter(
(staff): staff is Nurse => "nursingLicenseNumber" in staff
);
و وقتی ماوس را روی nursingLicenseNumbers
نگه دارید، TypeScript آن را بهجای []any
بهدرستی بهعنوان []string
استنتاج میکند:
const nursingLicenseNumbers: string[] = nurses.map((nurse) => nurse.nursingLicenseNumber);
یکی دیگر از راه های توصیه شده برای رسیدگی به این موضوع، تعریف تابع guard نوع است. یک تابع guard نوع دارای:
یک مقدار بازگشتی که به یک بولی ارزیابی می شود
یک نوع پردیکت
کد زیر از یک نوع guard تابع isStaff
استفاده می کند:
const isStaff = (staff: MedicalStaff): staff is Nurse =>
"nursingLicenseNumber" in staff;
const nurses = staffMembers.filter(isStaff);
const nursingLicenseNumbers = nurses.map((nurse) => nurse.nursingLicenseNumber);
console.log(nursingLicenseNumbers)
در مثال، تابع محافظ نوع ()isStaff
را از تابع ()filter
در مثال قبلی به تابع isStaff
تعریف می کنید. سپس ()filter
را با تابع ()isStaff
به عنوان آرگومان فراخوانی می کنید.
میتوانید از تابع ()isStaff
در مکانهای دیگری که به یک گزاره نوع مشابه نیاز دارند، دوباره استفاده کنید.
اگر میخواهید به ویژگیهایی دسترسی داشته باشید که مختص نوع MedicalStaff
هستند، میتوانید از محافظ نوع isStaff
در یک عبارت if
استفاده کنید:
const surgicalNurse: MedicalStaff = {
type: "NURSE",
name: "Jane Doe",
nursingLicenseNumber: "RN479312",
};
if (isStaff(surgicalNurse)) {
console.log(surgicalNurse.nursingLicenseNumber);
}
TypeScript نوع را به نوع Nurse
محدود می کند. میتوانید با نگه داشتن ماوس روی متغیر SurgicalNurse
ببینید.
مشکلات مربوط به گاردهای نوع سفارشی
یک guard نوع سفارشی می تواند بسیاری از مشکلات را هنگام فیلتر کردن آرایه ای از انواع میکس برطرف کند. با این حال، این یک راه حل خطا نیست و یک مسئله دارد که باید از آن آگاه باشید تا بهترین استفاده را از آن ببرید.
مسئله این است که تایپ اسکریپت اهمیتی نمی دهد که پیاده سازی درست باشد. این می تواند به شما احساس راحتی کاذب بدهد که در حال نوشتن کد ایمن هستید.
مثال زیر را در نظر بگیرید:
const isStaff = (staff: any) : staff is Nurse => true;
const nurses = staffMembers.filter(isStaff);
const nursingLicenseNumbers = nurses.map(nurse => nurse.nursingLicenseNumber);
console.log(nursingLicenseNumbers)
تابع ()isStaff
بررسی نمی کند که آیا هیچ یک از اشیاء موجود در آرایه دارای ویژگی nursingLicenseNumber
است یا خیر، و با این حال TypeScript به ما هشدار نمی دهد. این ما را گمراه می کند تا باور کنیم که اجرای درست است.
این ممکن است مانند یک اشکال در TypeScript به نظر برسد، اما این یک انتخاب طراحی است که میتواند در مشکل TypeScript GitHub پیدا شود.
برای اطمینان از داشتن کد ایمن، باید اجرای تابع type guard را بررسی کنید تا مطمئن شوید که آنها به خوبی پیادهسازی شدهاند، زیرا TypeScript راهحل ساختهشدهای ندارد که بتواند این مشکل را علامتگذاری کند.
نتیجه
در این آموزش، نحوه فیلتر کردن مقادیر در یک آرایه با استفاده از TypeScript را یاد گرفتید. ابتدا یاد گرفتید که چگونه یک آرایه را با عناصری از نوع یکسان فیلتر کنید. سپس اقدام به فیلتر کردن یک آرایه حاوی عناصری از انواع میکس میکنید که مسائل استنتاج را مطرح میکند. از آنجا، ما از یک گارد نوع سفارشی استفاده کردیم تا به TypeScript کمک کنیم تا آرایه ای از انواع میسک را در طول فیلتر کردن به درستی استنتاج کند. برای ادامه سفر TypeScript خود، از آرشیو وبلاگ ما دیدن کنید.