العربية

استكشف أنواع Partial في TypeScript، وهي ميزة قوية لإنشاء خصائص اختيارية، وتبسيط التعامل مع الكائنات، وتعزيز قابلية صيانة الكود بأمثلة عملية.

إتقان أنواع TypeScript الجزئية (Partial): تحويل الخصائص لمرونة أكبر

TypeScript، وهي مجموعة شاملة من JavaScript، تجلب الكتابة الثابتة (static typing) إلى عالم تطوير الويب الديناميكي. إحدى ميزاتها القوية هي النوع Partial، الذي يسمح لك بإنشاء نوع تكون فيه جميع خصائص نوع موجود اختيارية. تفتح هذه الإمكانية عالمًا من المرونة عند التعامل مع البيانات، ومعالجة الكائنات، والتفاعلات مع واجهات برمجة التطبيقات (APIs). يستكشف هذا المقال النوع Partial بعمق، ويقدم أمثلة عملية وأفضل الممارسات للاستفادة منه بفعالية في مشاريع TypeScript الخاصة بك.

ما هو نوع TypeScript الجزئي (Partial)؟

النوع Partial<T> هو نوع مساعد مدمج في TypeScript. يأخذ نوعًا T كوسيط عام (generic argument) ويعيد نوعًا جديدًا تكون فيه جميع خصائص T اختيارية. في جوهره، يحول كل خاصية من 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)

1. تحديث ملف تعريف المستخدم

تخيل أن لديك دالة تقوم بتحديث ملف تعريف مستخدم ما. لا تريد أن تطلب من الدالة استلام جميع خصائص المستخدم في كل مرة؛ بل تريد السماح بتحديثات لحقول معينة.


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> بتمرير الخصائص التي تحتاج إلى تحديث فقط دون التسبب في أخطاء النوع.

2. بناء كائن طلب لواجهة برمجة تطبيقات (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>، يمكنك إنشاء كائنات طلب بالمعلمات الضرورية فقط، مما يجعل الدالة أكثر تنوعًا.

3. إنشاء كائن نموذج (Form)

عند التعامل مع النماذج، خاصة النماذج متعددة الخطوات، يمكن أن يكون استخدام 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

لنفترض أنك تريد فقط أن تكون خصائص معينة من 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 هذه الاختلافات.


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 أداة متعددة الاستخدامات لإنشاء كود مرن وقابل للصيانة. من خلال السماح لك بتحديد خصائص اختيارية، فإنه يبسط معالجة الكائنات، والتفاعلات مع واجهات برمجة التطبيقات، والتعامل مع البيانات. يمكن أن يعزز فهم كيفية استخدام Partial بفعالية، إلى جانب تركيباته مع الأنواع المساعدة الأخرى، سير عمل تطوير TypeScript الخاص بك بشكل كبير. تذكر استخدامه بحكمة، وتوثيق غرضه بوضوح، والتحقق من صحة البيانات لتجنب المخاطر المحتملة. عند تطوير تطبيقات عالمية، ضع في اعتبارك المتطلبات المتنوعة للمناطق والثقافات المختلفة للاستفادة من أنواع Partial للحصول على حلول قابلة للتكيف وسهلة الاستخدام. من خلال إتقان أنواع Partial، يمكنك كتابة كود TypeScript أكثر قوة وقابلية للتكيف والصيانة يمكنه التعامل مع مجموعة متنوعة من السيناريوهات بأناقة ودقة.