البرمجة الوظيفية في TypeScript: من الألف إلى الياء
البرمجة الوظيفية (FP) هي نموذج برمجي ينظر إلى العمليات الحسابية على أنها تقييم للدوال الرياضية ويتجنب تغيير الحالة والبيانات القابلة للتغيير. TypeScript، كونه امتدادًا صارمًا للأنواع من JavaScript، يوفر أساسًا ممتازًا لتطبيق مبادئ البرمجة الوظيفية، مما يسمح بكتابة كود أكثر قابلية للتنبؤ والاختبار والموثوقية. في هذه المقالة، سنقوم بتحليل المفاهيم الأساسية للبرمجة الوظيفية في TypeScript، بدءًا من الأساسيات وحتى التقنيات المتقدمة.
المبادئ الأساسية للبرمجة الوظيفية
قبل التعمق في الكود، من المهم فهم المبادئ الأساسية التي تقوم عليها البرمجة الوظيفية.
الدوال النقية (Pure Functions)
الدالة النقية هي دالة:
- تعيد دائمًا نفس النتيجة لنفس الوسائط (الحتمية).
- ليس لها آثار جانبية (لا تغير المتغيرات الخارجية، ولا تطبع بيانات في وحدة التحكم، ولا ترسل طلبات).
مثال على دالة نقية:
function add(a: number, b: number): number { return a + b;}
// دائمًا يمكن التنبؤ بهاconsole.log(add(2, 3)); // 5console.log(add(2, 3)); // 5مثال على دالة غير نقية:
let counter = 0;function increment(): number { return ++counter; // تأثير جانبي: تغيير متغير خارجي}الثبات (Immutability)
يجب ألا تتغير البيانات بعد إنشائها. بدلاً من تعديل الكائن الموجود، نقوم بإنشاء نسخة جديدة منه مع التغييرات اللازمة.
interface User { name: string; age: number;}
const user: User = { name: "Alice", age: 30 };
// سيء (تحوير)user.age = 31;
// جيد (ثبات)const updatedUser: User = { ...user, age: 31 };
console.log(user); // { name: "Alice", age: 30 } - الأصل لم يتغيرconsole.log(updatedUser); // { name: "Alice", age: 31 }التركيب والكاري في TypeScript
تركيب الدوال هو عملية دمج عدة دوال بسيطة لإنشاء دالة أكثر تعقيدًا. الكاري (currying) هو تحويل دالة ذات عدة وسائط إلى سلسلة من الدوال، كل منها تأخذ وسيطًا واحدًا.
التركيب (Function Composition)
تطبيق موصوف الأنواع للتركيب في TypeScript:
function compose<A, B, C>(f: (x: B) => C, g: (x: A) => B): (x: A) => C { return (x: A) => f(g(x));}
const toUpperCase = (str: string): string => str.toUpperCase();const exclaim = (str: string): string => `${str}!`;
const shout = compose(exclaim, toUpperCase);console.log(shout("hello world")); // "HELLO WORLD!"الكاري (Currying)
مثال على دالة مكاريّة:
function multiply(a: number): (b: number) => number { return (b: number) => a * b;}
const double = multiply(2);const triple = multiply(3);
console.log(double(5)); // 10console.log(triple(5)); // 15الكاري يجعل الدوال أكثر مرونة وسهولة في التركيب.
العمل مع المونادات: Option و Result
المونادات هي نمط قوي للتعامل مع الآثار الجانبية ومعالجة الأخطاء دون انتهاك نقاء الدوال. في TypeScript، غالبًا ما تُستخدم المونادات Option (أو Maybe) و Result (أو Either).
مونادة Option (Maybe)
تسمح بالعمل بأمان مع القيم التي قد تكون null أو undefined.
type Option<T> = T | null;
function safeDivide(a: number, b: number): Option<number> { return b === 0 ? null : a / b;}
function getValue(value: Option<number>): string { if (value === null) { return "خطأ: القسمة على صفر"; } return `النتيجة: ${value}`;}
console.log(getValue(safeDivide(10, 2)