با تایپهای Partial در TypeScript، یک ویژگی قدرتمند برای ایجاد خصوصیات اختیاری، سادهسازی کار با اشیاء و بهبود نگهداری کد با مثالهای عملی و بهترین شیوهها آشنا شوید.
تسلط بر تایپهای Partial در TypeScript: تبدیل خصوصیات برای انعطافپذیری
TypeScript، به عنوان یک بالامجموعه از جاوااسکریپت، تایپدهی استاتیک را به دنیای پویای توسعه وب میآورد. یکی از ویژگیهای قدرتمند آن، تایپ Partial
است که به شما امکان میدهد یک تایپ جدید بسازید که در آن تمام خصوصیات یک تایپ موجود اختیاری هستند. این قابلیت، دنیایی از انعطافپذیری را هنگام کار با دادهها، دستکاری اشیاء و تعاملات API باز میکند. این مقاله به طور عمیق به بررسی تایپ Partial
میپردازد و مثالهای عملی و بهترین شیوهها را برای استفاده مؤثر از آن در پروژههای TypeScript شما ارائه میدهد.
تایپ Partial در TypeScript چیست؟
تایپ Partial<T>
یک تایپ کاربردی داخلی (utility type) در TypeScript است. این تایپ یک تایپ T
را به عنوان آرگومان جنریک خود میگیرد و یک تایپ جدید برمیگرداند که در آن تمام خصوصیات T
اختیاری (optional) هستند. در اصل، این تایپ هر خصوصیت را از حالت required
(اجباری) به optional
(اختیاری) تبدیل میکند، به این معنی که هنگام ایجاد یک شیء از آن تایپ، لزومی به وجود داشتن آنها نیست.
مثال زیر را در نظر بگیرید:
interface User {
id: number;
name: string;
email: string;
country: string;
}
const user: User = {
id: 123,
name: "Alice",
email: "alice@example.com",
country: "USA",
};
حالا، بیایید یک نسخه Partial
از تایپ User
بسازیم:
type PartialUser = Partial<User>;
const partialUser: PartialUser = {
name: "Bob",
};
const anotherPartialUser: PartialUser = {
id: 456,
email: "bob@example.com",
};
const emptyUser: PartialUser = {}; // معتبر است
در این مثال، PartialUser
دارای خصوصیات id?
، name?
، email?
و country?
است. این بدان معناست که شما میتوانید اشیائی از نوع PartialUser
با هر ترکیبی از این خصوصیات، یا حتی بدون هیچکدام از آنها، ایجاد کنید. انتساب emptyUser
این موضوع را نشان میدهد و جنبه کلیدی Partial
را برجسته میکند: این تایپ تمام خصوصیات را اختیاری میکند.
چرا از تایپهای Partial استفاده کنیم؟
تایپهای Partial
در چندین سناریو ارزشمند هستند:
- بهروزرسانی تدریجی اشیاء: هنگام بهروزرسانی یک شیء موجود، اغلب فقط میخواهید زیرمجموعهای از خصوصیات آن را تغییر دهید.
Partial
به شما امکان میدهد که محتوای بهروزرسانی را فقط با خصوصیاتی که قصد تغییرشان را دارید، تعریف کنید. - پارامترهای اختیاری: در پارامترهای توابع،
Partial
میتواند پارامترهای خاصی را اختیاری کند و انعطافپذیری بیشتری در نحوه فراخوانی تابع فراهم آورد. - ساختن اشیاء در چند مرحله: هنگام ساختن یک شیء پیچیده، ممکن است تمام دادهها به یکباره در دسترس نباشند.
Partial
به شما این امکان را میدهد که شیء را به صورت قطعه به قطعه بسازید. - کار با APIها: APIها اغلب دادههایی را برمیگردانند که در آنها ممکن است فیلدهای خاصی وجود نداشته باشند یا null باشند.
Partial
به مدیریت این شرایط بدون اعمال سختگیرانه تایپها کمک میکند.
مثالهای عملی از تایپهای Partial
۱. بهروزرسانی پروفایل کاربر
تصور کنید تابعی دارید که پروفایل یک کاربر را بهروزرسانی میکند. شما نمیخواهید این تابع هر بار مجبور به دریافت تمام خصوصیات کاربر باشد؛ در عوض، میخواهید اجازه دهید فیلدهای خاصی بهروز شوند.
interface UserProfile {
firstName: string;
lastName: string;
age: number;
country: string;
occupation: string;
}
function updateUserProfile(userId: number, updates: Partial<UserProfile>): void {
// شبیهسازی بهروزرسانی پروفایل کاربر در پایگاه داده
console.log(`Updating user ${userId} with:`, updates);
}
updateUserProfile(1, { firstName: "David" });
updateUserProfile(2, { lastName: "Smith", age: 35 });
updateUserProfile(3, { country: "Canada", occupation: "Software Engineer" });
در این حالت، Partial<UserProfile>
به شما اجازه میدهد فقط خصوصیاتی را که نیاز به بهروزرسانی دارند، بدون ایجاد خطاهای تایپ، ارسال کنید.
۲. ساختن یک شیء درخواست برای API
هنگام ارسال درخواستهای API، ممکن است پارامترهای اختیاری داشته باشید. استفاده از Partial
میتواند ایجاد شیء درخواست را سادهتر کند.
interface SearchParams {
query: string;
category?: string;
location?: string;
page?: number;
pageSize?: number;
}
function searchItems(params: Partial<SearchParams>): void {
// شبیهسازی یک فراخوانی API
console.log("Searching with parameters:", params);
}
searchItems({ query: "laptop" });
searchItems({ query: "phone", category: "electronics" });
searchItems({ query: "book", location: "London", page: 2 });
در اینجا، SearchParams
پارامترهای جستجوی ممکن را تعریف میکند. با استفاده از Partial<SearchParams>
، میتوانید اشیاء درخواست را فقط با پارامترهای ضروری ایجاد کنید و تابع را کاربردیتر سازید.
۳. ایجاد یک شیء فرم
هنگام کار با فرمها، به ویژه فرمهای چند مرحلهای، استفاده از Partial
میتواند بسیار مفید باشد. شما میتوانید دادههای فرم را به عنوان یک شیء Partial
نمایش دهید و به تدریج با پر کردن فرم توسط کاربر، آن را تکمیل کنید.
interface AddressForm {
street: string;
city: string;
postalCode: string;
country: string;
}
let form: Partial<AddressForm> = {};
form.street = "123 Main St";
form.city = "Anytown";
form.postalCode = "12345";
form.country = "USA";
console.log("Form data:", form);
این رویکرد زمانی مفید است که فرم پیچیده باشد و کاربر ممکن است تمام فیلدها را به یکباره پر نکند.
ترکیب Partial با دیگر تایپهای کاربردی
Partial
را میتوان با دیگر تایپهای کاربردی TypeScript ترکیب کرد تا تبدیلات تایپ پیچیدهتر و سفارشیتری ایجاد شود. برخی از ترکیبات مفید عبارتند از:
Partial<Pick<T, K>>
: خصوصیات خاصی را اختیاری میکند.Pick<T, K>
زیرمجموعهای از خصوصیات را ازT
انتخاب میکند و سپسPartial
آن خصوصیات انتخاب شده را اختیاری میسازد.Required<Partial<T>>
: اگرچه به نظر متناقض میآید، اما این ترکیب برای سناریوهایی مفید است که میخواهید اطمینان حاصل کنید پس از «کامل» شدن یک شیء، تمام خصوصیات آن وجود دارند. شما ممکن است با یکPartial<T>
شروع به ساخت شیء کنید و سپس ازRequired<Partial<T>>
برای اعتبارسنجی اینکه تمام فیلدها قبل از ذخیره یا پردازش پر شدهاند، استفاده کنید.Readonly<Partial<T>>
: تایپی ایجاد میکند که در آن تمام خصوصیات هم اختیاری و هم فقط-خواندنی (read-only) هستند. این برای زمانی مفید است که نیاز به تعریف یک شیء دارید که میتواند به صورت جزئی پر شود اما پس از ایجاد اولیه نباید تغییر کند.
مثال: Partial با Pick
فرض کنید میخواهید فقط خصوصیات خاصی از User
در حین بهروزرسانی اختیاری باشند. میتوانید از Partial<Pick<User, 'name' | 'email'>>
استفاده کنید.
interface User {
id: number;
name: string;
email: string;
country: string;
}
type NameEmailUpdate = Partial<Pick<User, 'name' | 'email'>>;
const update: NameEmailUpdate = {
name: "Charlie",
// country در اینجا مجاز نیست، فقط name و email
};
const update2: NameEmailUpdate = {
email: "charlie@example.com"
};
بهترین شیوهها هنگام استفاده از تایپهای Partial
- با احتیاط استفاده کنید: در حالی که
Partial
انعطافپذیری ارائه میدهد، استفاده بیش از حد از آن میتواند منجر به بررسی تایپ کمتر سختگیرانه و خطاهای احتمالی در زمان اجرا شود. فقط زمانی از آن استفاده کنید که واقعاً به خصوصیات اختیاری نیاز دارید. - جایگزینها را در نظر بگیرید: قبل از استفاده از
Partial
، ارزیابی کنید که آیا تکنیکهای دیگری مانند تایپهای union یا تعریف خصوصیات اختیاری به طور مستقیم در اینترفیس، ممکن است مناسبتر باشند. - به وضوح مستندسازی کنید: هنگام استفاده از
Partial
، به وضوح دلیل استفاده از آن و اینکه کدام خصوصیات انتظار میرود اختیاری باشند را مستند کنید. این به سایر توسعهدهندگان کمک میکند تا هدف را درک کرده و از سوءاستفاده جلوگیری کنند. - دادهها را اعتبارسنجی کنید: از آنجایی که
Partial
خصوصیات را اختیاری میکند، اطمینان حاصل کنید که دادهها را قبل از استفاده اعتبارسنجی میکنید تا از رفتار غیرمنتظره جلوگیری شود. از type guardها یا بررسیهای زمان اجرا برای تأیید وجود خصوصیات مورد نیاز در مواقع ضروری استفاده کنید. - استفاده از الگوی سازنده (builder pattern) را در نظر بگیرید: برای ساخت اشیاء پیچیده، استفاده از الگوی سازنده را برای ایجاد شیء در نظر بگیرید. این روش اغلب میتواند جایگزین واضحتر و قابل نگهداریتری برای استفاده از `Partial` برای ساخت تدریجی یک شیء باشد.
ملاحظات و مثالهای جهانی
هنگام کار با برنامههای جهانی، ضروری است که در نظر بگیرید چگونه تایپهای Partial
میتوانند به طور مؤثر در مناطق و زمینههای فرهنگی مختلف استفاده شوند.
مثال: فرمهای آدرس بینالمللی
فرمتهای آدرس در کشورهای مختلف به طور قابل توجهی متفاوت است. برخی کشورها به اجزای آدرس خاصی نیاز دارند، در حالی که برخی دیگر از سیستمهای کد پستی متفاوتی استفاده میکنند. استفاده از Partial
میتواند این تفاوتها را پوشش دهد.
interface InternationalAddress {
streetAddress: string;
apartmentNumber?: string; // در برخی کشورها اختیاری است
city: string;
region?: string; // استان، ایالت و غیره
postalCode: string;
country: string;
addressFormat?: string; // برای مشخص کردن فرمت نمایش بر اساس کشور
}
function formatAddress(address: InternationalAddress): string {
let formattedAddress = "";
switch (address.addressFormat) {
case "UK":
formattedAddress = `${address.streetAddress}\n${address.city}\n${address.postalCode}\n${address.country}`;
break;
case "USA":
formattedAddress = `${address.streetAddress}\n${address.city}, ${address.region} ${address.postalCode}\n${address.country}`;
break;
case "Japan":
formattedAddress = `${address.postalCode}\n${address.region}${address.city}\n${address.streetAddress}\n${address.country}`;
break;
default:
formattedAddress = `${address.streetAddress}\n${address.city}\n${address.postalCode}\n${address.country}`;
}
return formattedAddress;
}
const ukAddress: Partial<InternationalAddress> = {
streetAddress: "10 Downing Street",
city: "London",
postalCode: "SW1A 2AA",
country: "United Kingdom",
addressFormat: "UK"
};
const usaAddress: Partial<InternationalAddress> = {
streetAddress: "1600 Pennsylvania Avenue NW",
city: "Washington",
region: "DC",
postalCode: "20500",
country: "USA",
addressFormat: "USA"
};
console.log("UK Address:\n", formatAddress(ukAddress as InternationalAddress));
console.log("USA Address:\n", formatAddress(usaAddress as InternationalAddress));
اینترفیس InternationalAddress
فیلدهای اختیاری مانند apartmentNumber
و region
را برای سازگاری با فرمتهای مختلف آدرس در سراسر جهان مجاز میداند. فیلد addressFormat
میتواند برای سفارشیسازی نحوه نمایش آدرس بر اساس کشور استفاده شود.
مثال: ترجیحات کاربر در مناطق مختلف
ترجیحات کاربر میتواند در مناطق مختلف متفاوت باشد. برخی از ترجیحات ممکن است فقط در کشورها یا فرهنگهای خاصی مرتبط باشند.
interface UserPreferences {
darkMode: boolean;
language: string;
currency: string;
timeZone: string;
pushNotificationsEnabled: boolean;
smsNotificationsEnabled?: boolean; // در برخی مناطق اختیاری است
marketingEmailsEnabled?: boolean;
regionSpecificPreference?: any; // ترجیح انعطافپذیر مختص منطقه
}
function updateUserPreferences(userId: number, preferences: Partial<UserPreferences>): void {
// شبیهسازی بهروزرسانی ترجیحات کاربر در پایگاه داده
console.log(`Updating preferences for user ${userId}:`, preferences);
}
updateUserPreferences(1, {
darkMode: true,
language: "en-US",
currency: "USD",
timeZone: "America/Los_Angeles"
});
updateUserPreferences(2, {
darkMode: false,
language: "fr-CA",
currency: "CAD",
timeZone: "America/Toronto",
smsNotificationsEnabled: true // در کانادا فعال است
});
اینترفیس UserPreferences
از خصوصیات اختیاری مانند smsNotificationsEnabled
و marketingEmailsEnabled
استفاده میکند که ممکن است فقط در مناطق خاصی مرتبط باشند. فیلد regionSpecificPreference
انعطافپذیری بیشتری برای افزودن تنظیمات مختص منطقه فراهم میکند.
نتیجهگیری
تایپ Partial
در TypeScript ابزاری همهکاره برای ایجاد کدی انعطافپذیر و قابل نگهداری است. با اجازه دادن به تعریف خصوصیات اختیاری، دستکاری اشیاء، تعاملات API و مدیریت دادهها را ساده میکند. درک نحوه استفاده مؤثر از Partial
، همراه با ترکیبات آن با سایر تایپهای کاربردی، میتواند به طور قابل توجهی گردش کار توسعه TypeScript شما را بهبود بخشد. به یاد داشته باشید که از آن با احتیاط استفاده کنید، هدف آن را به وضوح مستند کنید و دادهها را برای جلوگیری از مشکلات احتمالی اعتبارسنجی کنید. هنگام توسعه برنامههای جهانی، نیازهای متنوع مناطق و فرهنگهای مختلف را در نظر بگیرید تا از تایپهای Partial
برای راهحلهای سازگار و کاربرپسند بهرهبرداری کنید. با تسلط بر تایپهای Partial
، میتوانید کدی قویتر، سازگارتر و قابل نگهداریتر در TypeScript بنویسید که بتواند با ظرافت و دقت، انواع سناریوها را مدیریت کند.