العربية

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

أنواع القوالب الحرفية في TypeScript لواجهات برمجة تطبيقات آمنة من حيث النوع

تُعد أنواع القوالب الحرفية (Template Literal Types) في TypeScript ميزة قوية تم تقديمها في الإصدار 4.1 من TypeScript، وهي تتيح لك إجراء معالجة للسلاسل النصية على مستوى النوع. تفتح هذه الميزة عالمًا من الإمكانيات لإنشاء واجهات برمجة تطبيقات (APIs) عالية الأمان وقابلة للصيانة، مما يمكنك من اكتشاف الأخطاء في وقت التصريف (compile time) بدلاً من أن تظهر فقط في وقت التشغيل (runtime). وهذا بدوره يؤدي إلى تحسين تجربة المطور، وتسهيل إعادة هيكلة الكود، وإنشاء كود أكثر قوة.

ما هي أنواع القوالب الحرفية؟

في جوهرها، أنواع القوالب الحرفية هي أنواع سلاسل نصية حرفية (string literal types) يمكن بناؤها من خلال الجمع بين أنواع السلاسل النصية الحرفية، وأنواع الاتحاد (union types)، ومتغيرات الأنواع. فكر فيها كأنها استيفاء للسلاسل النصية (string interpolation) ولكن للأنواع. يتيح لك هذا إنشاء أنواع جديدة بناءً على الأنواع الموجودة، مما يوفر درجة عالية من المرونة والتعبيرية.

إليك مثال بسيط:

type Greeting = "Hello, World!";

type PersonalizedGreeting<T extends string> = `Hello, ${T}!`;

type MyGreeting = PersonalizedGreeting<"Alice">; // type MyGreeting = "Hello, Alice!"

في هذا المثال، PersonalizedGreeting هو نوع قالب حرفي يأخذ معامل نوع عام T، والذي يجب أن يكون سلسلة نصية. ثم يقوم ببناء نوع جديد عن طريق استيفاء السلسلة النصية الحرفية "Hello, " مع قيمة T والسلسلة النصية الحرفية "!". النوع الناتج، MyGreeting، هو "Hello, Alice!".

فوائد استخدام أنواع القوالب الحرفية

حالات استخدام واقعية

1. تعريف نقاط نهاية واجهة برمجة التطبيقات (API Endpoint)

يمكن استخدام أنواع القوالب الحرفية لتعريف أنواع نقاط نهاية واجهة برمجة التطبيقات، مما يضمن تمرير المعاملات الصحيحة إلى الواجهة ومعالجة الاستجابة بشكل صحيح. لنفترض وجود منصة تجارة إلكترونية تدعم عملات متعددة، مثل الدولار الأمريكي (USD)، واليورو (EUR)، والين الياباني (JPY).

type Currency = "USD" | "EUR" | "JPY";
type ProductID = string; // عمليًا، يمكن أن يكون هذا نوعًا أكثر تحديدًا

type GetProductEndpoint<C extends Currency> = `/products/${ProductID}/${C}`;

type USDEndpoint = GetProductEndpoint<"USD">; // type USDEndpoint = "/products/${string}/USD"

يُعرّف هذا المثال نوع GetProductEndpoint الذي يأخذ عملة كمعامل نوع. النوع الناتج هو نوع سلسلة نصية حرفية يمثل نقطة نهاية الواجهة لاسترداد منتج بالعملة المحددة. باستخدام هذا النهج، يمكنك ضمان بناء نقطة نهاية الواجهة دائمًا بشكل صحيح واستخدام العملة الصحيحة.

2. التحقق من صحة البيانات

يمكن استخدام أنواع القوالب الحرفية للتحقق من صحة البيانات في وقت التصريف. على سبيل المثال، يمكنك استخدامها للتحقق من تنسيق رقم هاتف أو عنوان بريد إلكتروني. تخيل أنك بحاجة إلى التحقق من صحة أرقام الهواتف الدولية التي يمكن أن يكون لها تنسيقات مختلفة بناءً على رمز البلد.

type CountryCode = "+1" | "+44" | "+81"; // الولايات المتحدة، المملكة المتحدة، اليابان
type PhoneNumber<C extends CountryCode, N extends string> = `${C}-${N}`;

type ValidUSPhoneNumber = PhoneNumber<"+1", "555-123-4567">; // type ValidUSPhoneNumber = "+1-555-123-4567"

// ملاحظة: قد يتطلب التحقق الأكثر تعقيدًا الجمع بين أنواع القوالب الحرفية والأنواع الشرطية.

يوضح هذا المثال كيف يمكنك إنشاء نوع رقم هاتف أساسي يفرض تنسيقًا معينًا. قد يتضمن التحقق الأكثر تعقيدًا استخدام أنواع شرطية وأنماط شبيهة بالتعبيرات النمطية (regular expression) داخل القالب الحرفي.

3. توليد الكود

يمكن استخدام أنواع القوالب الحرفية لتوليد الكود في وقت التصريف. على سبيل المثال، يمكنك استخدامها لتوليد أسماء مكونات React بناءً على اسم البيانات التي تعرضها. من الأنماط الشائعة توليد أسماء المكونات التي تتبع نمط <Entity>Details.

type Entity = "User" | "Product" | "Order";
type ComponentName<E extends Entity> = `${E}Details`;

type UserDetailsComponent = ComponentName<"User">; // type UserDetailsComponent = "UserDetails"

يتيح لك هذا توليد أسماء مكونات متسقة ووصفية تلقائيًا، مما يقلل من خطر تضارب الأسماء ويحسن قابلية قراءة الكود.

4. معالجة الأحداث

تعتبر أنواع القوالب الحرفية ممتازة لتعريف أسماء الأحداث بطريقة آمنة من حيث النوع، مما يضمن تسجيل مستمعي الأحداث بشكل صحيح وتلقي معالجات الأحداث للبيانات المتوقعة. لنفترض وجود نظام يتم فيه تصنيف الأحداث حسب الوحدة (module) ونوع الحدث، مفصولة بنقطتين رأسيتين.

type Module = "user" | "product" | "order";
type EventType = "created" | "updated" | "deleted";
type EventName<M extends Module, E extends EventType> = `${M}:${E}`;

type UserCreatedEvent = EventName<"user", "created">; // type UserCreatedEvent = "user:created"

interface EventMap {
  [key: EventName<Module, EventType>]: (data: any) => void; // مثال: النوع الخاص بمعالجة الحدث
}

يوضح هذا المثال كيفية إنشاء أسماء أحداث تتبع نمطًا ثابتًا، مما يحسن الهيكل العام وأمان النوع لنظام الأحداث.

تقنيات متقدمة

1. الجمع مع الأنواع الشرطية

يمكن دمج أنواع القوالب الحرفية مع الأنواع الشرطية لإنشاء تحويلات أنواع أكثر تطورًا. تتيح لك الأنواع الشرطية تعريف أنواع تعتمد على أنواع أخرى، مما يمكنك من تنفيذ منطق معقد على مستوى النوع.

type ToUpperCase<S extends string> = S extends Uppercase<S> ? S : Uppercase<S>;

type MaybeUpperCase<S extends string, Upper extends boolean> = Upper extends true ? ToUpperCase<S> : S;

type Example = MaybeUpperCase<"hello", true>; // type Example = "HELLO"
type Example2 = MaybeUpperCase<"world", false>; // type Example2 = "world"

في هذا المثال، يأخذ MaybeUpperCase سلسلة نصية وقيمة منطقية (boolean). إذا كانت القيمة المنطقية صحيحة (true)، فإنه يحول السلسلة النصية إلى أحرف كبيرة؛ وإلا، فإنه يعيد السلسلة كما هي. يوضح هذا كيف يمكنك تعديل أنواع السلاسل النصية بشكل شرطي.

2. الاستخدام مع الأنواع المعينة (Mapped Types)

يمكن استخدام أنواع القوالب الحرفية مع الأنواع المعينة لتحويل مفاتيح نوع الكائن. تتيح لك الأنواع المعينة إنشاء أنواع جديدة عن طريق التكرار على مفاتيح نوع موجود وتطبيق تحويل على كل مفتاح. من حالات الاستخدام الشائعة إضافة بادئة أو لاحقة إلى مفاتيح الكائن.

type MyObject = {
  name: string;
  age: number;
};

type AddPrefix<T, Prefix extends string> = {
  [K in keyof T as `${Prefix}${string & K}`]: T[K];
};

type PrefixedObject = AddPrefix<MyObject, "data_">;
// type PrefixedObject = {
//    data_name: string;
//    data_age: number;
// }

هنا، يأخذ AddPrefix نوع كائن وبادئة. ثم يقوم بإنشاء نوع كائن جديد بنفس الخصائص، ولكن مع إضافة البادئة إلى كل مفتاح. يمكن أن يكون هذا مفيدًا لتوليد كائنات نقل البيانات (DTOs) أو أنواع أخرى حيث تحتاج إلى تعديل أسماء الخصائص.

3. أنواع معالجة السلاسل النصية المدمجة

توفر TypeScript العديد من أنواع معالجة السلاسل النصية المدمجة، مثل Uppercase، وLowercase، وCapitalize، وUncapitalize، والتي يمكن استخدامها بالاقتران مع أنواع القوالب الحرفية لإجراء تحويلات أكثر تعقيدًا للسلاسل النصية.

type MyString = "hello world";

type CapitalizedString = Capitalize<MyString>; // type CapitalizedString = "Hello world"

type UpperCasedString = Uppercase<MyString>;   // type UpperCasedString = "HELLO WORLD"

تسهل هذه الأنواع المدمجة إجراء عمليات معالجة السلاسل النصية الشائعة دون الحاجة إلى كتابة منطق أنواع مخصص.

أفضل الممارسات

الأخطاء الشائعة

البدائل

بينما توفر أنواع القوالب الحرفية طريقة قوية لتحقيق أمان النوع في تطوير واجهات برمجة التطبيقات، هناك مناهج بديلة قد تكون أكثر ملاءمة في مواقف معينة.

الخاتمة

تُعد أنواع القوالب الحرفية في TypeScript أداة قيمة لإنشاء واجهات برمجة تطبيقات آمنة من حيث النوع وقابلة للصيانة. فهي تتيح لك إجراء معالجة للسلاسل النصية على مستوى النوع، مما يمكنك من اكتشاف الأخطاء في وقت التصريف وتحسين الجودة الإجمالية للكود الخاص بك. من خلال فهم المفاهيم والتقنيات التي تمت مناقشتها في هذا المقال، يمكنك الاستفادة من أنواع القوالب الحرفية لبناء واجهات برمجة تطبيقات أكثر قوة وموثوقية وسهولة للمطورين. سواء كنت تبني تطبيق ويب معقدًا أو أداة بسيطة لسطر الأوامر، يمكن لأنواع القوالب الحرفية مساعدتك في كتابة كود TypeScript أفضل.

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