سلام دوستان امیدوارم حالتون خوب باشه. این اولین مقاله من تو ویرگوله که درباره نوشتن یوتیلیتی تایپ های کاستوم در تایپ اسکریپته. اولین مقاله رو با تایپ اسکریپت شروع کردم چون این روزا طرفدارای زیادی تو سراسر دنیا پیدا کرده ولی مطلب فارسی در موردش خیلی کمه و یه جورایی داره در حقش احجاف میشه. خب حرفای حاشیه ای بسه بریم یه مقدمه کوچیک و بعدش هم مطلب اصلی.
تایپ اسکریپت بطور built-in دارای تعدادی utility type پابه ای هستش و پیاده سازی سایر یوتیلیتی تایپ های کاستوم رو به عهده برنامه نویس ها گذاشته. ما هم قراره تو این مطلب چند تا یوتیلیتی تایپ سفارشی پرکاربرد رو پیاده سازی کنیم ولی پیش نیازش دونستن جنریک ها و چند یوتیلیتی تایپ built-in مثل Required, Partial, Pick و Omit هستش که قبل از شروع مختصر درباره شون توضیح میدم.
فلسفه و منطق به وجود اومدن جنریک ها نوشتن تابپ های resusable بوده، به این صورت که یک تایپ بتونه بعنوان ورودی یک یا چند تایپ دیگه رو بگیره و تایپ جدیدی رو بهمون برگردونه. تو مثال زیر اینترفیس ServerResponse بعنوان ورودی تایپ T رو میگیره و نوع پراپرتی data رو برابر با آرایه ای از T ها قرار میده.
interface ServerResponse<T> { message: string; hasError: boolean; data: T[] }
حالا که با مفهوم جنریک آشنا شدیم کمی با یوتیلیتی تایپ های built-inیی که بالا بهشون اشاره کردیم آشنا میشیم
1. Required<T>
به عنوان ورودی یک تایپ رو میگیره و پراپرتی های اون رو به حالت اجباری در میاره. در کد زیر RequiredUserType و RequiredUserInterface با هم معادلند
type RequiredUserType = Required<UserInterface> interface RequiredUserInterface { email: string; firstName: string; lastName: string; age: number; phone: string; address: string }
2. Partial<T>
تایپ T رو میگیره و پراپرتی های موجود اون رو به حالت Optional درمیاره. در کد زیر PartialUserType و PartialUserInterface با هم معادلند.
type PartialUserType = Partial<UserInterface> interface PartialUserInterface { email?: string; firstName?: string; lastName?: string; age?: number; phone?: string; address?: string }
3. Pick<T, P extends keyof T>
به عنوان ورودی تایپ و unionی از پراپرتی های موجود در اون تایپ رو میگیره و تایپ خروجی، تایپیه که شامل اون پراپرتی هایه. در کد زیر PickUserType و PickUserInterface با هم معادلند.
type PickUserType = Pick<UserInterface, 'email' | 'phone'> interface PickUserInterface { email: string; phone?: string; }
4. Omit<T, P extends keyof T>
به عنوان ورودی تایپ و unionی از پراپرتی های موجود در اون تایپ رو میگیره و تایپ خروجی، تایپیه که شامل اون پراپرتی نباشه. در کد زیرOmitUserType و UserInterface باهم معادلند.
type OmitUserType = Omit<UserInterface, 'firstName' | 'lastName'> interface OmitUserInterface { email: string; age: number; phone?: string; address?: string }
تفاوت RequiredUserType و UserInterface در این هست که پراپرتی های اون به حالت اجباری در اومده
تفاوت PartialUserType و UserInterface در این هست که پراپرتی های اون به حالت اختیاری در اومده
تفاوت PickUserType و UserInterface در این هست که فقط شامل email و phone هست
تفاوت OmitUserType و UserInterface در این هست که شامل پراپرتی های firstName و lastName نیست
خب حالا بریم سر اصل مطلب
همونطور که میبنید در UserInterface پراپرتی های lastName و phone و address اختیاری و email و firstName و age اجباری هستند.
حالا چند تا نیازمندی مطرح میکنم و میریم ببینیم چجوری میشه بهشون پاسخ داد.
نبازمندی ۱: تایپی داشته باشیم که فقط پراپرتی های email و lastName اجباری و بقیه اختیاری باشه
نبازمندی ۲: تایپی داشته باشیم که فقط پراپرتی های lastName و age اختیاری و بقیه اجباری باشه
نیازمندی ۳: تایپی داشته باشیم که علاوه بر پراپرتی هایی که هم اکنون اختیاری هستند (lastName و phone و address )، پراپرتی age هم اختیاری بشه و بقیه بدون تغییر
نیازمندی ۴: تایپی داشته باشیم که علاوه بر پراپرتی هایی که هم اکنون اجباری هستند (email و firstName و age )، پراپرتی phone هم اجباری بشه و بقیه بدون تغییر
پاسخ نیازمندی ۱
type SomeRequired<T, P extends keyof T> = Required<Pick<T, P>> & Partial<Omit<T, P>> type Ans1 = SomeRequired<UserInterface, 'email' | 'lastName'>
به عنوان ورودی تایپ T و یونیونی از پراپرتی هاش گرفته می شه، در سمت چپ اپراتور & پراپرتی های پاس داده شده از تایپ T انتخاب شده و به حالت Required درمیان. در سمت راست & پراپرتی های پاس داده شده از تایپ T حذف شده و بقیه پراپرتی ها به حالت Partial در میان. این ۲ تایپ با هم combine میشوند (عملگر &) و تایپ مورد نظر ما بوجود میاد
مراحلی که قدم به قدم اتفاق میفته:
Required<Pick<UserInterface, 'email' | 'lastName'>> & Partial<Omit<UserInterface, 'email' | 'lastName'>> // => Required<{email: string; lastName?: string}> & Partial<{firstName: string; age: number; phone?: string; address?: string}> // => { email: string; lastName: string } & { firstName?: string; age?: number; phone?: string; address?: string } // => { email: string; lastName: string firstName?: string; age?: number; phone?: string; address?: string }
پاسخ نیازمندی ۲
type SomePartial<T, P extends keyof T> = Required<Omit<T, P>> & Partial<Pick<T, P>> type Ans2 = SomePartial<UserInterface, 'lastName' | 'age'>
به عنوان ورودی تایپ T و یونیونی از پراپرتی هاش گرفته می شه، در سمت چپ اپراتور & پراپرتی های پاس داده شده از تایپ T حذف شده و به حالت Required درمیان. در سمت راست & پراپرتی های پاس داده شده از تایپ T انتخاب شده و به حالت Partial در میان. این ۲ تایپ با هم combine میشن (عملگر &) و تایپ مورد نظر ما بوجود میاد.
مراحلی که اتفاق میفته:
Required<Omit<UserInterface, 'lastName' | 'age'>> & Partial<Pick<UserInterface, 'lastName' | 'age'>> // => Required<{email: string; firstName: string; phone?: string; address?: string}> & Partial<{lastName: string; age: number;}> // => { email: string; firstName: string; phone: string; address: string } & { lastName?: string; age?: number; } // => { email: string; firstName: string; lastName?: string age?: number; phone: string; address: string }
پاسخ نیازمندی ۳
type AddPartial<T, P extends keyof T> = Omit<T, P> & Partial<Pick<T, P>> type Ans3 = AddPartial<UserInterface, 'age'>
به عنوان ورودی تایپ T و یونیونی از پراپرتی هاش گرفته می شه، در سمت چپ اپراتور & پراپرتی های پاس داده شده از تایپ T حذف میشن. در سمت راست & پراپرتی های پاس داده شده از تایپ T انتخاب شده و به حالت Partial در میان. این ۲ تایپ با هم combine میشن (عملگر &) و تایپ مورد نظر ما بوجود میاد.
مراحلی که اتفاق میفته:
Omit<UserInterface, 'age'> & Partial<Pick<UserInterface, 'age'>> // => { email: string; firstName: string; lastName?: string; phone?: string; address?: string} & Partial<{age: number}> // => { email: string; firstName: string; lastName?: string; phone?: string; address?: string } & { age?: number; } // => { email: string; firstName: string; lastName?: string age?: number; phone?: string; address?: string }
پاسخ نیازمندی ۴
type AddRequired<T, P extends keyof T> = Omit<T, P> & Required<Pick<T, P>> type Ans4 = AddRequired<UserInterface, 'phone'>
به عنوان ورودی تایپ T و یونیونی از پراپرتی هاش گرفته می شه، در سمت چپ اپراتور & پراپرتی های پاس داده شده از تایپ T حذف میشن. در سمت راست & پراپرتی های پاس داده شده از تایپ T انتخاب شده و به حالت Required در میان. این ۲ تایپ با هم combine میشن (عملگر &) و تایپ مورد نظر ما بوجود میاد.
مراحلی که اتفاق میفته:
Omit<UserInterface, 'phone'> & Required<Pick<UserInterface, 'phone'>> // => { email: string; firstName: string; lastName?: string; age: number; address?: string} & Required<{phone?: number}> // => { email: string; firstName: string; lastName?: string; age: number; address?: string} & {phone: number} // => { email: string; firstName: string; lastName?: string; age: number; phone: string; address?: string }
امیدوارم خیلی بد توضیح نداده باشم که هیچکی هیچی نفهمه :)
اگه خطایی تو این محتوا دیدین خوشحال میشم که تو کامنت ها بهم تذکر بدین. خیلی ممنون از وقتی که برای مطالعه گذاشتید.