البرمجة الوظيفية في TypeScript: من النظرية إلى التطبيق
البرمجة الوظيفية (FP) هي نموذج برمجي يعتمد على الحوسبة من خلال تطبيق الدوال وتجنب تغيير الحالة. يوفر TypeScript، كونه مجموعة شاملة مكتوبة بشدة من JavaScript، أدوات قوية لتطبيق البرمجة الوظيفية. في هذه المقالة، سنقوم بتحليل المفاهيم الرئيسية للبرمجة الوظيفية في TypeScript مع أمثلة عملية للكود.
1. الدوال النقية وعدم القابلية للتغيير
الدالة النقية هي دالة:
- تعيد نفس النتيجة لنفس الوسائط (الحتمية).
- ليس لها تأثيرات جانبية (لا تعدل متغيرات خارجية، ولا تقوم بعمليات إدخال/إخراج).
// دالة نقيةconst add = (a: number, b: number): number => a + b;
// دالة غير نقية (تأثير جانبي — تعديل حالة خارجية)let counter = 0;const increment = (): number => ++counter;عدم القابلية للتغيير يعني أن البيانات لا تتغير، بل يتم إنشاء نسخ جديدة. في TypeScript، يمكنك استخدام عامل الانتشار وطرق عدم التعديل:
interface User { name: string; age: number;}
// التعديل (سيء)const updateAgeMutable = (user: User, newAge: number): void => { user.age = newAge;};
// النهج غير القابل للتغيير (جيد)const updateAgeImmutable = (user: User, newAge: number): User => ({ ...user, age: newAge,});عدم القابلية للتغيير يبسط تصحيح الأخطاء والاختبار، حيث أن البيانات متوقعة دائمًا.
2. الدوال عالية المستوى والإغلاقات
الدوال عالية المستوى هي دوال تأخذ دوال أخرى كوسائط أو تعيدها. مثال على ذلك طريقة Array.map:
const numbers: number[] = [1, 2, 3, 4];const doubled: number[] = numbers.map((x) => x * 2);console.log(doubled); // [2, 4, 6, 8]الإغلاق هو دالة "تتذكر" المتغيرات من نطاقها الخارجي حتى بعد انتهاء تنفيذ الدالة الخارجية:
const createMultiplier = (factor: number): ((x: number) => number) => { return (x: number) => x * factor;};
const double = createMultiplier(2);const triple = createMultiplier(3);
console.log(double(5)); // 10console.log(triple(5)); // 15تُستخدم الإغلاقات على نطاق واسع لإنشاء دوال ذات تطبيق جزئي للوسائط (التحويل إلى سلسلة دوال).
3. تركيب الدوال والتحويل إلى سلسلة دوال
تركيب الدوال هو دمج عدة دوال في دالة واحدة، حيث يكون ناتج دالة واحدة هو الإدخال للدالة التالية. في TypeScript، يمكنك كتابة أداة مساعدة للتركيب:
const compose = <T, R>(...fns: Array<(arg: T) => T>) => (arg: T): T => fns.reduceRight((acc, fn) => fn(acc), arg);
// مثال: تحويل نصconst toUpperCase = (s: string): string => s.toUpperCase();const exclaim = (s: string): string => `${s}!`;const shout = compose(toUpperCase, exclaim);
console.log(shout("hello")); // "HELLO!"التحويل إلى سلسلة دوال هو تحويل دالة ذات وسائط متعددة إلى سلسلة من الدوال ذات وسيط واحد:
// دالة عاديةconst add = (a: number, b: number): number => a + b;
// النسخة المحولة إلى سلسلة دوالconst curriedAdd = (a: number) => (b: number): number => a + b;
const add5 = curriedAdd(5);console.log(add5(3)); // 8التحويل إلى سلسلة دوال يبسط إنشاء دوال متخصصة ويحسن قابلية إعادة استخدام الكود.
4. المونادات والعمل مع Option/Maybe
الموناد هو نمط برمجة وظيفي يغلف قيمة ويوفر واجهة لتحويلها. أحد أبسط المونادات هو Maybe (أو Option)، الذي يعالج n