Structural Typing چیست و چگونه Typescript را متمایز میکند؟

تایپ اسکریپت به این شکل خود را معرفی میکند: «فوق‌مجموعه (Superset) جاوااسکریپت به همراه سیستم تایپ استاتیک». در صورتی که از زبان جاوا اسکریپت به تایپ اسکریپت مهاجرت کرده باشید احتمالا از تجربه بی‌دردسر و راحت این کار تعجب کرده باشید اما دقیقا ندانید دلیل این راحتی چیست. در صورتی که از زبان‌هایی همچون جاوا و سی‌شارپ ترغیب شده باشید تا تایپ اسکریپت را امتحان کنید، احتمالا تا الان با تفاوت های سیستم تایپ تایپ‌اسکریپت با زبان های نام‌برده آشنا شده باشید. در این نوشته میخواهم به این موارد بپردازم.

به طور کلی اول باید ببینیم که منظورم از استاتیک تایپ چیست؟ به طور کلی اگه بخواهیم زبان‌ها را دسته‌بندی کنیم، با دو نوع سیستم تایپ مواجه میشویم: 1- استاتیک تایپ  2- داینامیک تایپ

اگر بخواهیم وارد جزئیات نشویم، به طور کلی داینامیک تایپ به این معناست که درستی و همخوانی مقادیر و متغیرها در ران‌تایم بررسی میشود در حالی که در Static Typing، چک کردن تایپ ها یا Type Checking  در زمان کامپایل صورت میگیرد. زبان هایی مثل JS یا پایتون از دینامیک تایپ بهره میبرند. برنامه‌نویس‌ها معمولا از آن‌ها به عنوان زبان‌های بدون تایپ نام میبرند چون عملا کمکی به برنامه‌نویس هنگام نوشتن برنامه نمیشود.

حال باید با یکی دیگر از دسته‌بندی های رایج تایپ‌سیستم‌ها آشنا بشویم: 1- Structural Typing 2- Nominative Typing.

چیزی که تایپ‌اسکریپت را از زبان‌های نظیر جاوا و Rust متمایز میکند دقیقا در همین دسته‌بندی بالاست، جایی که تایپ‌اسکریپت از نوع Structural Typing پشتیبانی میکند در حالی که زبان های مذکور از تایپ سیستم‌های Nominative.

حال بیاید ببینیم که منظور از Structural Typing چیست؟ تایپ‌سیستم های Structural برای تشخیص سازگاری و تخصیص تایپ ها به یکدیگر بر مبنای ساختار تایپ و پراپرتی‌های موجود در آنها تصمیم میگیرند و به اسم و محل اعلان تایپ‌ها توجهی نمیشود. در حالی که در سیستم های Nominative همانطور که از اسم آن برمیاید، به نام تایپ‌ها و محل اعلان آنها دقت میشود. حرف زدن کافیه (و cheapه طبق گفته آن بزرگوار) و بذارید کد را نشان بدهم.

interface Person1 {
  name: string;
  age: number;
}

interface Person2 {
  name: string;
  age: number;
}

let person1 : Person1;

let person2 : Person2 = {
  name: "Mahdi",
  age: 21,
};

person1 = person2;

همانطور که در کد بالا واضح است، Person1 و Person2 دو تایپ کاملا متفاوت اما با ساختار و Structure مشابه‌ن. به همین دلیل متغیر با تایپ Person2 به متغیر person1 با تایپ Person1 نسبت داده شده است.

در زبان‌های مشابه جاوا و دیگر زبان‌هایی که Nominative هستن، دو متغیر person1 و person2 به یکدیگر قابل assign نیستند.

چرا تایپ‌اسکریپت Structurally Typed است؟

برمیگردیم به اولین پاراگراف نوشته؛ طراحی تایپ‌اسکریپت به شکلی صورت گرفته که مهاجرت از جاوااسکریپت به تایپ‌اسکریپت به ساده‌ترین شکل صورت بگیرد. به همین دلیل لازم است که تایپ‌اسکریپت بسیار مشابه جاوا اسکریپت رفتار کند. همانطور که میدانید هر برنامه‌ی جاوااسکریپتی به شکل پیش‌فرض تایپ‌اسکریپت هم میباشد، برای رسیدن به این هدف تنها گزینه موجود برای تیم مهندسی تایپ‌اسکریپت استفاده از Structural Typing بوده است چون جاوااسکریپت نیز از مکانیزمی مشابه آن به نام Duck Typing بهره میبرد.

شاعر آمریکایی جیمز رایلی در جمله‌ای مشهور گفته است: «زمانی که پرنده‌ای را می‌بینم که مثل اردک راه می‌رود، مثل اردک شنا می‌کند و مثل اردک کواک کواک می‌کند، من این پرنده را اردک می‌نامم.» ریشه تکنیک Duck Typing در طراحی تایپ‌سیستم‌ها هم میشود گفت که از همینجا می‌آید. زبان‌های همچون جاوااسکریپت و پایتون در صورتی که یک آبجکت در ران‌تایم متدها و پراپرتی‌هایی که لازم است داشته باشد را داشته باشد، آنگاه دیگر بدون توجه به نوع آبجکت، آن آبجکت را از لحاظ تایپ مناسب میداند. مثال زیر از پایتون رو نگاه کنید.

class Duck:
    def fly(self):
        print("Duck flying")

class Sparrow:
    def fly(self):
        print("Sparrow flying")

class Whale:
    def swim(self):
        print("Whale swimming")

for animal in Duck(), Sparrow(), Whale():
    animal.fly()

# Output:

# Duck flying
# Sparrow flying
# AttributeError: 'Whale' object has no attribute 'fly'

همانطور که دیدید، شاید اصلی ترین دلیلی که استفاده از Structural Typing را در طراحی تایپ اسکریپت ناگزیر کرده است؛ طراحی تایپ‌سیستم جاوااسکریپت به شکل Duck Typing است.

دیدگاهتان را بنویسید