چیزی که من خیلی بابتش هیجان زده‌ام:TypeScript 4.0

ترجمه و تالیف : محمدرضا مصلی
تاریخ انتشار : 14 آبان 99
خواندن در 5 دقیقه
دسته بندی ها : جاوا اسکریپت

در تاریخ 20 آگوست، تیم پشتیبان TypeScript رسما نسخه 4.0 خود را منتشر کرد. این نسخه پیشرفته‌ترین زبان، مفسر و حتی وبسایت آن‌ها تا به امروز است و با اعلام این خبر ، لیستی از به روزرسانی‌ها ارائه شد که به طور شگفت انگیزی برای تغییر عمده نسخه بود که تعداد آن‌ها زیاد نبود. آن‌ها تغییرات عمده‌ای هستند که نیاز به کار طراحی زیاد و ساعت‌های کدنویسی زیادی توسط بسیاری از افراد دارند و در این مقاله قصد دارم موارد اصلی را بیان کنم، اگر می‌خواهید نسخه رسمی را با همه تغییراتی بخوانید، می‌توانید اینجا کلیک کنید.

بنابراین بدون هیچ زحمت بیشتری، به لیست تغییراتی که بیشتر از همه هیجان زده‌ام بروم ، میایید؟

برای یادگیری TypeScript،می‌توانید از دوره TypeScript وبسایت راکت استفاده کنید.

استنباط ویژگی کلاس از سازنده

شماره یک لیست این است. هر بار زبان (یا مفسر) به نفع شما کار می‌کند تا در وقت و کلید شما صرفه جویی کند، من طرفدار این ویژگی هستم. TypeScript در حال انجام تحلیل جریان کنترل است تا بفهمد چه نوع مقادیری را به خصوصیات کلاس خود اختصاص می‌دهید. اگر تجزیه و تحلیل بتواند مشخص کند که هیچ مسیر غیرقابل دسترسی وجود ندارد، پس می‌تواند انواع آن‌ها را فرض کند.

بگذارید با یک مثال سریع توضیح دهم:

//Clear paths, so this works and assumes "string" for all properties
class Person {
  full_name;
  first_name;
  last_name;
  
  contructor(full_name: string) {
    this.full_name = full_name;
    this.first_name = full_name.split(" ")[0]
    this.last_name = full_name.split(" ")[1]
  }
}

//This doesn't work since not all paths are clear
class Person {
  full_name;
  first_name;
  last_name;
  
  contructor(full_name: string) {
    this.full_name = full_name;
    if(Math.random()) {
      this.first_name = full_name.split(" ")[0]
      this.last_name = full_name.split(" ")[1]
    }
  }
}

نسخه دوم کلاس دارای یک مسیر کد (عبارت IF) است که همیشه مورد استفاده قرار نمی‌گیرد، به این معنی که first_name و last_name همیشه مقداری را با این کد اختصاص نمی‌دهند. و به همین دلیل مفسر TypeScript نمی‌تواند نوع را برای آن‌ها استنباط کند. اولین مثال، با وجود مسیرهای کد روشن، یک نمونه کامل از چگونگی جلوگیری از نیاز به تعریف انواع و اجازه دادن به مفسر برای استنباط آن‌ها از منطق شما است.

المنت دوقلو با برچسب

این به روزرسانی نسبتاً کوچک‌تری در مقایسه با نسخه قبلی است اما اکنون می‌توانید المنت موجود خود را برچسب گذاری کنید.

اساساً آنچه این تغییر به آن پرداخته این واقعیت است که اگر تابعی را با پارامتر رست تعریف کنید، هنگام خواندن امضای آن تابع یا حتی هنگام خواندن نکات مهم IDE برای آن تابع، هدف واقعی آن کاملاً روشن نیست. به تصویر زیر نگاه کنید:

در این راهنما ، parama_0 و params_1 بیان می‌شود، در این حالت برای چنین تابع ساده‌ای مهم نیست، اما می‌توانید ببینید که برای یک تابع پیچیده‌تر، نداشتن نام برای این پارامترها چگونه به خوانایی آسیب می‌رساند. بنابراین با TypeScript ۴، اکنون می‌توانید برچسب‌ها را اضافه کنید و یک راهنمای بهبود یافته مانند این خواهید داشت:

اما یک ثانیه صبر کنید، این تنها کاربرد این برچسب ها نیست. با تشکر از آن‌ها، اکنون می‌توانید بیش از حد در نوع، نوع خود را بدون هیچ مشکلی ایجاد کنید:

این راهنما هر سه بار اضافی را نشان می‌دهد و به لطف برچسب‌ها، معنی آن‌ها نسبت به چیزی که پارامتر صفر: رشته، پارامتر یک: عدد را می‌گوید بسیار معنی دار‌تر خواهد بود.

چند ملاحظه در مورد برچسب‌های چندتایی:

  1. اگر برای یک مورد چندتایی از برچسب استفاده می‌کنید، باید از آن‌ها برای همه المان‌ها استفاده کنید.
  2. همچنین می‌توانید با استفاده از برچسب، پارامتر اختیاری تعریف کنید البته در انتهای آن:
type Person = [name: string, address?: string]

انواع متنوع چندتایی

این یکی اسم خیلی جالبی داره، نه؟ مدتی طول کشید تا آن را درک کنم، اما بگذارید مرحله به مرحله پیش برویم.

ما قبلاً مفهوم چندتایی را توضیح داده‌ایم، اما فقط برای اطمینان، چندتایی اساساً لیستی با طول از پیش تعیین شده و نوع هر المان شناخته شده است. بنابراین موارد زیر معتبر هستند:

type PersonParams = [name: string, age: number]
let me:PersonParams = ['Fernando Doglio', 36]

چندتایی‌ها، همانطور که در بالا مشاهده کردیم، اکنون می‌توانند المان را نیز نامگذاری کنند، اما نکته‌ای که در مورد آن‌ها وجود دارد، داشتن این ساختار از پیش تعیین شده است که می‌توانیم از آن برای تعریف پارامتر باقی مانده یک تابع استفاده کنیم (باز هم، تا حدودی در بالا پوشش داده شد، اما اجازه دهید توضیح بیشتری بدهم):

type PersonParams = [name: string, age: number]

function createPerson(...params: PersonParams): void {
  //... logic goes here
}

function createPerson(city: string, postalCode: string, ...otherParameters: PersonParams): void {
  ///.... logic goes here
}​

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

در حقیقت، با چندتایی‌های متغیر، می‌توان انواع عمومی را نیز تعریف کرد، که به ما اجازه می‌دهد تا چندتایی‌های نیمه تعریف شده ایجاد کنیم، جایی که می‌توان فضای انعطاف پذیری را ایجاد کرد، اجازه دهید توضیح دهم:

 
type FlexibleType<T extends unknown[]> = [string, ...T, string]

type AllStrings = FlexibleType<[string]> //this allows for [string, string, string]
type StringAndNumber = FlexibleType<[number]> //... [string, number, string]
type StringAndBools = FlexibleType<[bool, bool]> ///....[string, bool, bool, string]

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

عالی و جالب است، اما در واقع با این کار چه کاری می‌توانیم انجام دهیم؟ خوب اگر این انعطاف پذیری را برای تعریف ویژگی تابع اعمال کنید، می‌توانید الگوها را تعریف کنید. به عنوان مثال، داشتن یک تماس مجدد به عنوان آخرین پارامتر، یک الگوی بسیار رایج در نود‌جی‌اس با توابع غیر‌همزمان است. می‌توانید چنین چیزی را با چندتایی‌های متغیر در TypeScript تعریف کنید:

/// Generic variadic tuples
type CallbackFn<T extends unknown[]> = (Error, [...T]) => any;

type AsyncFn<T extends unknown[]> = (...arguments: [...T, CallbackFn<T>]) => any;

//Using the tuples

/**
 *  readFile('filename.txt', (err: Error, content: string) => {
     //.... my logic
 *  })
 */
const readFile: AsyncFn<[string]> = (filename: string, 
                                     cb: CallbackFn<[string]>) => { }; 

class DbRecord {

}

/**
 * dbQuery('select ? from ? where id = ?', ['*', 'tablename', 123], (err: Error,  results: DbRecord[]) => {
     ///.... my logic here
 * })
 */
const dbQuery: AsyncFn<[string,any[]]> = (queryString: string, 
                                          values: any[], 
                                          cb: CallbackFn<[DbRecord[]]>) => void {
    
}

همانطور که مشاهده می‌کنید، من در واقع دو چندتایی در بالای کد تعریف کردم، یکی برای توابع callback، زیرا یک الگوی کاملاً شناخته شده وجود دارد که اولین آرگومان خطا است و دومی (و بطور بالقوه سایر موارد) حاوی داده‌ها است. "مسیر شاد" (جایی که هیچ خطایی وجود ندارد). دومی از الگو استفاده می‌کند و یک الگوی جدید ایجاد می‌کند که در آن تابع callback آخرین المان در یک لیست پارامترهای نامشخص است.

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

بنابراین، در انتها، چندتایی‌های متغیر برای ساده کردن روش تعریف یک چندتایی عمومی اینجا هستند، سپس می‌توانیم از آن در هر کجا استفاده کنیم.

برخی از اصلاحات ویرایشگر

غیر از تغییرات فوق (و سایر تغییرات جزئی که من در اینجا ذکر نمی‌کنم)، نسخه ۴ برخی تغییرات خاص ویرایشگر را به خود اضافه کرده است، مانند:

تبدیل به زنجیره‌ای اختیاری

در صورتی که نمی‌دانید زنجیره‌ اختیاری چیست، یک ویژگی جدید از جاوا‌اسکریپت وجود دارد، که به شما امکان می‌دهد کد دسترسی ملک خود (یا تماس با روش زنجیره‌ای خود) را به صورت زنجیره‌ای بنویسید که اگر یکی از آن‌ها وجود ندارد (یا صفر یا تعریف نشده برمی‌گرداند، بنابراین زنجیره را کوتاه می‌کند) و کد یک استثنا ناخوشایند را ایجاد نمی‌کند (می‌توانید اطلاعات بیشتر را در اینجا بخوانید).

قبل از این ویژگی، شما باید مطمئن شوید که هر مرحله قبل از اتصال نهایی زنجیره قبل از دسترسی واقعی به آن وجود دارد، چیزی مانند:

obj.a && obj.a.b && obj.a.b.c && obj.a.b.c.d()

اکنون ، می‌توانید آن کد را انتخاب کرده و بر روی "تبدیل به عبارت زنجیره‌ای اختیاری" کلیک کنید و ویرایشگر آن کد را برای شما بازسازی می‌کند.

توجه داشته باشید که این مورد با استفاده از TypeScript ۴ در Visual Studio Code تست شده است، من نمی‌دانم ویرایشگرهای دیگر چگونه می‌توانند این تغییر را کنترل کنند.

پشتیبانی از /** @deprecated */

به شما این امکان را می‌دهد که نظرات خود را در بالای متد‌ها یا کارکردهایی که سعی در استرداد آن‌ها دارید اضافه کنید و ویرایشگر هنگام پیشنهاد گزینه‌های تکمیل خودکار، اخطار مربوطه را صادر می‌کند:

به نام تابع توجه کنید، این بدان معناست که دیگر نباید از آن استفاده کنید.

باز هم، این آزمون با استفاده از VS Code انجام شد، ویرایشگران دیگر ممکن است نحوه رسیدگی به این اعلان را تغییر دهند.

شکستن تغییرات

سرانجام ، می‌خواهم قبل از بستن این مقاله، به سرعت تغییرات اساسی در این نسخه را بررسی کنم، زیرا این مواردی هستند که ممکن است بیشتر روی شما تاثیر بگذارند.

تعریف نوع DOM تغییر می‌کند

تعریف lib.d.ts، آن‌ها باعث حذف شی document.origin می‌شود. این کار انجام شد زیرا فقط با نسخه‌های قدیمی IE و Safari کار می‌کرد. در عوض باید از self.origin برای همان نتیجه استفاده کنید.

غلبه بر دسترسی‌های با خواص

این فقط در صورتی که از گزینه useDefineForClassField استفاده کرده باشید خطا خواهد بود، اما اکنون جایگزینی دسترسی به املاک خود با یک ویژگی (و عکس آن) نیز همیشه خطا خواهد بود:

class BaseClass {
    get foo() {
        return 100;
    }
    set foo() {
        // ...
    }
}

class Derived extends BaseClass {
    foo = 10; //WRONG!: foo is an accessor, you can't override it here
}

///////////////////////////////////////////////////////

class BaseClass {
    prop = 10;
}

class Derived extends BaseClass {
    get prop() { //WRONG!: foo is a property already, you can't override it here
       return 100;
    }
}
 

فقط حذف ویژگی‌های اختیاری

اکنون، هر چیزی که می‌خواهید با اپراتور حذف کنید باید اختیاری باشد (در واقع ، یا اختیاری ، یا از انواع any، unknown یا never ). اگر در مورد آن فکر کنید منطقی است، زیرا اگر قصد حذف چیزی را دارید، باید چیز مشخصی باشد که ممکن است در یک مرحله از اجرای کد شما تعریف نشود، در غیر این صورت ممکن است رفتار غیرقابل پیش‌بینی را مشاهده کنید، دقیقاً برعکس آنچه در وهله اول سعی در دستیابی به آن را داریم.

نتیجه

چند مورد جزئی وجود دارد که من کنار گذاشته‌ام، عمدتا به این دلیل که آن‌ها تاثیر چندانی نداشته‌اند اما دوباره، اگر می‌خواهید لیست کامل تغییرات را ببینید، بیانیه رسمی آن‌ها را بررسی کنید.

نظر شما در مورد ویژگی‌های جدید TypeScript ۴ چیست؟ آیا از شروع استفاده از آن هیجان زده‌اید؟ می‌دانم که هستید! کدام مورد علاقتان است؟ مال من، قطعاً چندتایی‌های متنوع است، من دوست دارم بتوانم الگوهای عمومی را تعریف کنم که سپس در همه جا قابل استفاده و تخصصی باشد!

منبع

گردآوری و تالیف محمدرضا مصلی
آفلاین
user-avatar

حدود ۶ سالی هست که دارم برنامه نویسی میکنم و به دلیل علاقه زیادی که به زبان جاوا اسکریپت داشتم، به سمت تکنولوژی nodejs و فریم ورک های آن رفتم و همچنان در این حوزه فعالیت میکنم و دوست دارم تجربه خودم را با دیگران به اشتراک بگذارم.

دیدگاه‌ها و پرسش‌ها

برای ارسال نظر لازم است ابتدا وارد سایت شوید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید