
في تطوير واجهات برمجة التطبيقات (APIs) باستخدام Express.js و TypeScript، يعد تعريف الثوابت وإدارتها بشكل فعال أمرًا بالغ الأهمية للحفاظ على جودة الكود، وتحسين قابلية القراءة، وتقليل الأخطاء المحتملة. يركز هذا المقال على تقديم حلول عملية لتعريف قوائم الثوابت والتحقق من أن قيمة متغير ما تقع ضمن هذه القوائم، مع التركيز على أفضل الممارسات الهندسية.
لماذا تعريف الثوابت في واجهات برمجة تطبيقات TypeScript Express؟
يساهم تعريف الثوابت في تحسين العديد من جوانب جودة الكود. أولاً، يزيد من قابلية القراءة من خلال استبدال "الأرقام السحرية" أو السلاسل النصية المتكررة بأسماء ذات معنى. ثانيًا، يعزز سهولة الصيانة؛ فإذا تغيرت قيمة ثابت، يكفي تعديله في مكان واحد فقط. أخيرًا، ومع استخدام TypeScript، توفر الثوابت التحقق من النوع (Type Safety) في وقت التصريف، مما يقلل بشكل كبير من الأخطاء في وقت التشغيل.
يُعد استخدام TypeScript مع Express.js ميزة قوية، حيث يضيف طبقة من الأمان والوضوح إلى تطبيقك، خاصة عند التعامل مع البيانات المدخلة والمخرجة.
تعريف قوائم الثوابت في TypeScript
هناك عدة طرق لتعريف قوائم الثوابت في TypeScript، كل منها يناسب سيناريوهات مختلفة. سنستعرض أبرز هذه الطرق مع أمثلة عملية.
1. استخدام التعدادات (Enums)
تُعد التعدادات طريقة ممتازة لتعريف مجموعة من القيم المتصلة. يمكن أن تكون قيمها رقمية أو نصية.
<mark class='block' data-before='تعريف تعداد للأدوار:'>export enum UserRole {
ADMIN = "admin",
EDITOR = "editor",
VIEWER = "viewer",
}</mark>
<mark class='block' data-before='استخدام التعداد:'>const currentUserRole: UserRole = UserRole.ADMIN;
console.log(currentUserRole); // "admin"</mark>
معلومة!
تُنشئ التعدادات كائنات JavaScript في وقت التشغيل، مما يتيح لك الوصول إلى القيم والأسماء بسهولة.
2. استخدام أنواع الاتحاد (Union Types) مع الأنواع الحرفية (Literal Types)
هذه الطريقة توفر تعريفًا خفيف الوزن لمجموعة محددة من القيم، وتُعد مفيدة للتحقق من النوع في وقت التصريف.
<mark class='block' data-before='تعريف نوع اتحاد للأدوار:'>export type AllowedUserRole = "admin" | "editor" | "viewer";
</mark>
<mark class='block' data-before='استخدام نوع الاتحاد:'>const userPermission: AllowedUserRole = "editor";
// const invalidPermission: AllowedUserRole = "guest"; // خطأ في التصريف</mark>
3. استخدام مصفوفات أو كائنات `const` مع `as const`
عندما تحتاج إلى قائمة من الثوابت التي يمكن تكرارها أو استخدامها كمرجع في وقت التشغيل، فإن استخدام مصفوفات أو كائنات `const` مع `as const` هو الخيار الأمثل. يخبر `as const` TypeScript بمعاملة القيم كأنواع حرفية (literal types)، مما يجعل المصفوفة أو الكائن "للقراءة فقط" (read-only) ويحسن التحقق من النوع.
<mark class='block' data-before='تعريف مصفوفة ثوابت للحالات:'>export const VALID_ORDER_STATUSES = [
"pending",
"processing",
"shipped",
"delivered",
"cancelled",
] as const;
</mark>
<mark class='block' data-before='تعريف كائن ثوابت لنقاط النهاية:'>export const API_ENDPOINTS = {
USERS: "/api/users",
PRODUCTS: "/api/products",
ORDERS: "/api/orders",
} as const;
</mark>
استخدام `as const` يحول المصفوفة أو الكائن إلى نوع للقراءة فقط، مما يمنع التعديل غير المقصود على القيم في وقت التشغيل.
التحقق مما إذا كانت قيمة متغير موجودة في القائمة
بعد تعريف قوائم الثوابت، الخطوة التالية هي التحقق مما إذا كانت قيمة متغير معين تقع ضمن هذه القوائم. هذا أمر شائع في التحقق من صحة المدخلات (validation) في واجهات برمجة التطبيقات.
1. التحقق باستخدام التعدادات (Enums)
يمكنك استخدام `Object.values()` للحصول على مصفوفة من قيم التعداد ثم استخدام `.includes()` للتحقق.
import { Request, Response, NextFunction } from 'express';
import { UserRole } from '../constants/user-roles'; // افتراض أنك عرفت UserRole enum
<mark class='block green' data-before='+'>export const checkUserRole = (allowedRoles: UserRole[]) => {
return (req: Request, res: Response, next: NextFunction) => {
const userRole = req.headers['x-user-role'] as string; // افتراض أن الدور يأتي من الهيدر
if (!userRole || !Object.values(UserRole).includes(userRole as UserRole)) {
return res.status(403).send('Invalid or missing user role.');
}
if (!allowedRoles.includes(userRole as UserRole)) {
return res.status(403).send('Access denied.');
}
next();
};
};</mark>
<mark class='block' data-before='استخدام الوسيط في Express:'>// app.get('/admin-dashboard', checkUserRole([UserRole.ADMIN]), (req, res) => {
// res.send('Welcome to the admin dashboard!');
// });</mark>
2. التحقق باستخدام مصفوفات `const`
تُعد هذه الطريقة الأكثر مباشرة وفعالية للتحقق من وجود قيمة في قائمة محددة من الثوابت، مع الحفاظ على التحقق من النوع بفضل `as const`.
import { VALID_ORDER_STATUSES } from '../constants/app-settings';
<mark class='block green' data-before='+'>export function isValidOrderStatus(status: string): status is typeof VALID_ORDER_STATUSES[number] {
return (VALID_ORDER_STATUSES as readonly string[]).includes(status);
}</mark>
<mark class='block' data-before='مثال على الاستخدام في معالج مسار Express:'>import { Request, Response } from 'express';
export const updateOrderStatus = (req: Request, res: Response) => {
const { id } = req.params;
const { newStatus } = req.body;
if (!isValidOrderStatus(newStatus)) {
return res.status(400).send(`Invalid status: ${newStatus}. Allowed statuses are: ${VALID_ORDER_STATUSES.join(', ')}`);
}
// منطق تحديث الحالة في قاعدة البيانات
res.status(200).send(`Order ${id} updated to ${newStatus}`);
};</mark>
باستخدام `status is typeof VALID_ORDER_STATUSES[number]`، فإننا نُعلم TypeScript أن المتغير `status`، بعد اجتياز التحقق، سيكون من أحد الأنواع الحرفية المحددة في المصفوفة، مما يوفر تحكمًا قويًا بالنوع.
يُعد تعريف الثوابت والتحقق منها جزءًا لا يتجزأ من بناء واجهات برمجة تطبيقات قوية وموثوقة باستخدام Express.js و TypeScript. من خلال تطبيق هذه الأساليب، يمكنك تعزيز قابلية صيانة الكود، وتقليل الأخطاء، وتحسين تجربة المطور بشكل عام.
المشاركات ذات الصلة
المقال الأصلي:
إدارة الثوابت والتحقق منها في واجهات برمجة تطبيقات Express.js باستخدام TypeScript
المصدر: صوان محور XYZ
شكر خاص لـ GEMINI و جمال الحزازي.