مكتبة neverthrow لـ TypeScript: نوع Result لمعالجة الأخطاء
1. ما هي ولماذا تحتاجها
في تطوير TypeScript الحديث، غالباً ما تتحول معالجة الأخطاء إلى فوضى من كتل try/catch المنتشرة في جميع أنحاء الكود. تقدم مكتبة neverthrow حلاً أنيقاً لهذه المشكلة، مستوحاة من لغات البرمجة الوظيفية مثل Rust و Haskell. توفر المكتبة نوع Result<T, E> الذي يمثل بوضوح النتيجة الناجحة (Ok) أو الخطأ (Err)، مما يجعل معالجة الأخطاء جزءاً من نظام الأنواع بدلاً من كونها تأثيراً جانبياً.
الهدف الرئيسي لـ neverthrow هو استبدال الاستثناءات الضمنية بأنواع صريحة. بدلاً من كتابة دالة قد ترمي استثناءً في أي لحظة، تقوم بإرجاع Result الذي سيجبرك مترجم TypeScript على معالجته. هذا يجعل الكود أكثر قابلية للتنبؤ، وأكثر أماناً، ويوثق نفسه بنفسه. لم تعد تتساءل أي الدوال قد ترمي خطأً — فنوع القيمة المرجعة يخبرك بذلك مباشرة.
المكتبة مفيدة بشكل خاص في المشاريع التي تتطلب موثوقية عالية: خدمات الخلفية، التطبيقات المالية، وأنظمة معالجة البيانات. كما أنها تتكامل بشكل ممتاز مع المفاهيم الوظيفية الأخرى مثل أنواع Option (Maybe)، ويمكن دمجها مع مكتبات مثل fp-ts. neverthrow ليست مجرد أداة، بل هي فلسفة لكتابة الكود حيث الأخطاء هي بيانات وليست حالات استثنائية.
2. التثبيت
تثبيت neverthrow في مشروع TypeScript/NPM:
npm install neverthrow
للمشاريع التي تستخدم yarn:
yarn add neverthrow
لـ pnpm:
pnpm add neverthrow
المكتبة مكتوبة بلغة TypeScript وتتضمن أنواعاً كاملة، لذلك لا حاجة لتثبيت @types إضافية. بعد التثبيت، يمكنك استيراد الأنواع والدوال الرئيسية:
import { ok, err, Result } from 'neverthrow';
3. بداية سريعة — مثال عملي بسيط
لنقم بإنشاء دالة بسيطة تقسم رقمين، ولكنها ترجع Result بدلاً من رمي استثناء عند القسمة على صفر:
import { ok, err, Result } from 'neverthrow';
// تعريف نوع الخطأ
type DivisionError = { message: string; code: number };
// دالة ترجع Result
function safeDivide(a: number, b: number): Result<number, DivisionError> {
if (b === 0) {
return err({ message: 'القسمة على صفر', code: 1001 });
}
return ok(a / b);
}
// الاستخدام
const result = safeDivide(10, 2);
// معالجة النتيجة
if (result.isOk()) {
console.log('النتيجة:', result.value); // النتيجة: 5
} else {
console.error('خطأ:', result.error.message); // لن يتم تنفيذها أبداً
}
const errorResult = safeDivide(10, 0);
if (errorResult.isErr()) {
console.error('خطأ:', errorResult.error.message); // خطأ: القسمة على صفر
}
يوضح هذا المثال الفكرة الأساسية: الدالة ترجع دائماً Result، والكود المستدعي ملزم بالتحقق مما إذا كانت النتيجة ناجحة قبل استخدام القيمة. لن يسمح لك مترجم TypeScript بالوصول إلى result.value دون تحقق.
4. الدوال/الطرق/الفئات الأساسية
4.1. ok(value) — إنشاء نتيجة ناجحة
التوقيع:
function ok<T, E = never>(value: T): Ok<T, E>
الوظيفة: تنشئ مثيلاً من Ok يمثل نتيجة ناجحة بالقيمة المعطاة.
مثال:
import { ok } from 'neverthrow';
const success = ok(42);
console.log(success.isOk()); // true
console.log(success.value); // 42