بررسی Type Predicate در تایپ اسکریپت

تایپ اسکریپت یک superset جاوااسکریپت است که ویژگی‌های بی‌شماری را برای کمک به توسعه‌دهندگان برای نوشتن کد ایمن و مستندسازی بهتر آن‌ها معرفی می‌کند. یکی از این ویژگی‌ها type predicate است. در این مقاله قصد داریم تا با مفهوم type predicate در تایپ اسکریپت آشنا شویم، بررسی کنیم که این ویژگی چرا مفید است و چگونه باید از آن در پروژه‌های خود استفاده کنیم.

Type Predicate چیست؟

یک type predicate تابعی است که تایپ بازگشتی آن یک مقدار بولین می‌باشد، که برای محدود کردن تایپ‌ها مورد استفاده قرار می‌گیرد. زمانی که تایپ اسکریپت نمی‌تواند به طور خودکار تایپ یک متغیر را استنتاج کند، یا زمانی که بررسی‌های تایپ پیچیده‌تری مورد نیاز است، استفاده از type predicate می‌تواند مفید باشد.

سینتکس تابع type predicate به شکل زیر می‌باشد:

function isOfType(arg: any): arg is Type {
    // ... logic
}

arg is Type سینتکس type predicate است. این کد به تایپ اسکریپت سیگنال می‌دهد که وقتی تابع مقدار true را return می‌کند، فراخوانی کننده تابع می‌تواند مطمئن شود که arg از نوع Type است.

چرا Type Predicateها مفید هستند؟

سناریویی را در نظر می‌گیریم که در آن یک union type (به عنوان مثال، string | number) داریم و می‌خواهیم کدهای مختلفی را بر اساس تایپ اجرا کنیم. روش استاندارد، استفاده از type guardها می‌باشد:

function processInput(input: string | number) {
    if (typeof input === 'string') {
        console.log(input.toUpperCase());
    } else {
        console.log(input.toFixed(2));
    }
}

در حالی که typeof و instanceof هر دو مفید هستند، اما همه موارد را پوشش نمی‌دهند. اینجاست که type predicateها مطرح می‌شوند. آن‌ها به توسعه‌دهندگان اجازه می‌دهند تا type guardهای سفارشی ایجاد کنند که تایپ‌ها را بر اساس منطق سفارشی محدود می‌کند.

بررسی مثال‌هایی از Type Predicate

مثال اول با Interface

فرض کنید دو interface Cat و Dog داریم و می‌خواهیم بررسی کنیم که آیا یک حیوان Cat است یا خیر:

interface Cat {
    purr(): void;
}

interface Dog {
    bark(): void;
}

function isCat(animal: Cat | Dog): animal is Cat {
    return (animal as Cat).purr !== undefined;
}

اکنون، هر زمان که از isCat در یک حالت شرطی استفاده می‌کنیم، تایپ اسکریپت تایپ آن را می‌داند:

const myPet: Cat | Dog = getPetSomehow();

if (isCat(myPet)) {
    myPet.purr(); // TypeScript knows `myPet` is a `Cat` here.
} else {
    myPet.bark();
}

مثال دوم با کلاس

به طور مشابه می‌توانیم از type predicate به همراه کلاس استفاده کنیم:

class Bird {
    fly() { /*...*/ }
}

class Fish {
    swim() { /*...*/ }
}

function isBird(pet: Bird | Fish): pet is Bird {
    return (pet as Bird).fly !== undefined;
}

احتیاط

مواردی که هنگام استفاده از type predicateها حتما باید به آن‌ها توجه داشته باشته باشیم عبارتند از:

  • اطمینان از دقت: منطق درون type predicate ما باید دقیق باشد. اگر منطق ادعا می‌کند که یک نمونه از یک تایپ خاصی است در حالی که این گونه نیست، می‌تواند منجر به ایجاد خطاهای زمان اجرا شود.
  • اعتماد تایپ اسکریپت: هنگامی که تابع type predicate مقدار true را return می‌کند، تایپ اسکریپت کاملاً به این مقدار اطمینان دارد، بنابراین این مقدار دوباره بررسی نمی‌شود. در نتیجه باید مطمئن شویم که predicateهای ما حتما درست باشند.
  • عدم وجود خروجی مستقیم: هدف اصلی type predicateها return کردن یک مقدار بولین برای استفاده توسعه‌دهنده نیست، بلکه ارائه اطلاعات تایپ به تایپ اسکریپت می‌باشد. آن‌ها در درجه اول برای بررسی تایپ وجود دارند نه برای بررسی‌های مربوط به زمان اجرا.

جمع‌بندی

  • type predicate تابعی است که تایپ‌ها را بر اساس مقدار بازگشتی خود محدود می‌کند.
  • سینتکس type predicate arg is Type است.
  • استفاده از type predicate به ویژه هنگام کار با union typeها و یا زمانی که typeof و instanceof کافی نیستند، بسیار مفید می‌باشد.
  • همیشه باید مطمئن شویم که منطق تابع type predicate دقیق باشد تا از ایجاد خطاهای احتمالی زمان اجرا جلوگیری نماییم.

دیدگاه‌ها:

MPLPanahi

مهر 16, 1403  در  9:47 ق.ظ

ممنون از این آموزش عالی تون خدا خیرتون بده
سوالی برام پیش اومد اگه ما بیشتر از دو تا حالت داشته باشیم یعنی مثلا بیشتر از دو تا pet داشته باشیم در این صورت در این قسطمت ( pet is Bird ) چی باید بنویسیم؟

سودا مجتهدی

مهر 17, 1403  در  3:19 ب.ظ

ممنون از توجهتون
به طور کلی در تایپ اسکریپت وقتی می‌خواییم تایپ دو تا مقدار رو نسبت به هم مقایسه کنیم بهتره که اونا رو به عنوان ویژگی‌های یک آبجکت در نظر بگیریم و سپس تایپ آبجکت رو به discriminated union تبدیل کنیم و با تست تایپ یک ویژگی، تایپ کل آبجکت رو مشخص کنیم. مطالعه این لینک برای درک بهتر می‌تونه مفید باشه.

افزودن دیدگاه جدید