البرمجة الوظيفية في TypeScript: الأساسيات والتطبيق العملي

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

البرمجة الوظيفية في TypeScript: من النظرية إلى التطبيق



البرمجة الوظيفية (FP) هي نموذج يتم فيه التعامل مع الحوسبة كتقييم للدوال الرياضية وتتجنب تغيير الحالة والبيانات القابلة للتغيير. TypeScript، كونها مجموعة شاملة من JavaScript، مناسبة تمامًا لتطبيق مبادئ FP بسبب نظام الكتابة الصارم ودعمها للدوال عالية المستوى. في هذه المقالة، سنقوم بتحليل المفاهيم الرئيسية للبرمجة الوظيفية في TypeScript ونوضح كيفية تطبيقها عمليًا.



1. الدوال النقية وعدم القابلية للتغيير



الدالة النقية هي دالة:

  • تعيد دائمًا نفس النتيجة لنفس الوسائط (حتمية).
  • ليس لها تأثيرات جانبية (لا تعدل المتغيرات الخارجية، لا تُخرج بيانات، لا تقوم بطلبات).


مثال على دالة نقية:

// دالة نقية: تجمع رقمينconst add = (a: number, b: number): number => a + b;

// تعيد دائمًا 5console.log(add(2, 3)); // 5console.log(add(2, 3)); // 5


عدم القابلية للتغيير هو المبدأ الذي لا يتم فيه تغيير البيانات بعد إنشائها. بدلاً من تعديل كائن موجود، يتم إنشاء كائن جديد.



// تحديث مصفوفة غير قابل للتغييرconst numbers: number[] = [1, 2, 3];

// خطأ (تغيير):numbers.push(4);

// صحيح (غير قابل للتغيير):const newNumbers = [...numbers, 4]; // [1,2,3,4]

// تحديث كائن غير قابل للتغييرinterface User { name: string; age: number;}

const user: User = { name: 'Alice', age: 30 };const updatedUser: User = { ...user, age: 31 }; // كائن جديد


2. تركيب الدوال والكاري



تركيب الدوال هو دمج دالتين أو أكثر في دالة جديدة. يتم تمرير نتيجة الدالة الأولى كوسيطة للدالة الثانية.



// تركيب دالتينconst compose = <T, U, V>(f: (x: U) => V, g: (x: T) => U) =>  (x: T): V => f(g(x));

const double = (x: number): number => x * 2;const increment = (x: number): number => x + 1;

const doubleThenIncrement = compose(increment, double);console.log(doubleThenIncrement(3)); // (3*2)+1 = 7


الكاري هو تحويل دالة ذات وسائط متعددة إلى سلسلة من الدوال ذات وسيطة واحدة.



// دالة عاديةconst multiply = (a: number, b: number): number => a * b;

// النسخة المُكريةconst curriedMultiply = (a: number) => (b: number): number => a * b;

const multiplyBy2 = curriedMultiply(2);console.log(multiplyBy2(5)); // 10console.log(multiplyBy2(7)); // 14


الكاري يبسط التطبيق الجزئي وإعادة استخدام الدوال.



3. المُرْفِقات والمونادات: Maybe و Either



المُرْفِق هو حاوية تنفذ طريقة map، مما يسمح بتطبيق دالة على القيمة داخل الحاوية. في TypeScript، المصفوفة هي مثال على المُرْفِق:



const numbers = [1, 2, 3];const doubled = numbers.map(x => x * 2); // [2, 4, 6]


الموناد هو مُرْفِق يقوم بالإضافة إلى ذلك بتنفيذ طريقة flatMap (أو bind) و of (أو return). تساعد المونادات في التعامل مع التأثيرات الجانبية والقيم الفارغة والأخطاء بدون استثناءات.



لنقم بتنفيذ موناد Maybe بسيط للتعامل الآمن مع القيم الفارغة/غير المعرفة:



// موناد Maybeclass Maybe<T> {  private constructor(private value: T | null) {}

static of<T>(value: T): Maybe<T> { return new Maybe(value); }

static none<T>(): Maybe<T> { return new Maybe<T>(null); }

map<U>(fn: (value: T) => U): Maybe<U> { if (this.value === null || this.value === undefined) { return Maybe.none(); } return M

المدونات

توصيات الكتب