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

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

Type Predicate چیست؟

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function isOfType(arg: any): arg is Type {
// ... logic
}
function isOfType(arg: any): arg is Type { // ... logic }
function isOfType(arg: any): arg is Type {
    // ... logic
}

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

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

سناریویی را در نظر می‌گیریم که در آن یک union type (به عنوان مثال،

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function processInput(input: string | number) {
if (typeof input === 'string') {
console.log(input.toUpperCase());
} else {
console.log(input.toFixed(2));
}
}
function processInput(input: string | number) { if (typeof input === 'string') { console.log(input.toUpperCase()); } else { console.log(input.toFixed(2)); } }
function processInput(input: string | number) {
    if (typeof input === 'string') {
        console.log(input.toUpperCase());
    } else {
        console.log(input.toFixed(2));
    }
}

در حالی که

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

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

مثال اول با Interface

فرض کنید دو interface

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
interface Cat {
purr(): void;
}
interface Dog {
bark(): void;
}
function isCat(animal: Cat | Dog): animal is Cat {
return (animal as Cat).purr !== undefined;
}
interface Cat { purr(): void; } interface Dog { bark(): void; } function isCat(animal: Cat | Dog): animal is Cat { return (animal as Cat).purr !== undefined; }
interface Cat {
    purr(): void;
}

interface Dog {
    bark(): void;
}

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

اکنون، هر زمان که از

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const myPet: Cat | Dog = getPetSomehow();
if (isCat(myPet)) {
myPet.purr(); // TypeScript knows `myPet` is a `Cat` here.
} else {
myPet.bark();
}
const myPet: Cat | Dog = getPetSomehow(); if (isCat(myPet)) { myPet.purr(); // TypeScript knows `myPet` is a `Cat` here. } else { myPet.bark(); }
const myPet: Cat | Dog = getPetSomehow();

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

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Bird {
fly() { /*...*/ }
}
class Fish {
swim() { /*...*/ }
}
function isBird(pet: Bird | Fish): pet is Bird {
return (pet as Bird).fly !== undefined;
}
class Bird { fly() { /*...*/ } } class Fish { swim() { /*...*/ } } function isBird(pet: Bird | Fish): pet is Bird { return (pet as Bird).fly !== undefined; }
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
    true را return می‌کند، تایپ اسکریپت کاملاً به این مقدار اطمینان دارد، بنابراین این مقدار دوباره بررسی نمی‌شود. در نتیجه باید مطمئن شویم که predicateهای ما حتما درست باشند.
  • عدم وجود خروجی مستقیم: هدف اصلی type predicateها return کردن یک مقدار بولین برای استفاده توسعه‌دهنده نیست، بلکه ارائه اطلاعات تایپ به تایپ اسکریپت می‌باشد. آن‌ها در درجه اول برای بررسی تایپ وجود دارند نه برای بررسی‌های مربوط به زمان اجرا.

جمع‌بندی

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

دیدگاه‌ها:

MPLPanahi

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

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

سودا مجتهدی

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

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

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