تایپ اسکریپت یک 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ها حتما باید به آن‌ها توجه داشته باشته باشیم عبارتند از:

جمع‌بندی