معالجة JSON في TypeScript: من العمليات الأساسية إلى التصنيف المتقدم
JSON (JavaScript Object Notation) يظل التنسيق الأساسي لتبادل البيانات في تطوير الويب. يضيف TypeScript إلى العمل مع JSON نظام أنواع قوي يسمح بتجنب العديد من الأخطاء في مرحلة التجميع. في هذه المقالة، سنشرح جميع جوانب معالجة JSON في TypeScript: من التحليل البسيط إلى إنشاء أدوات تحقق مصنفة بدقة.
التحليل والتسلسل الأساسيان
لنبدأ بالعمليات الأساسية. تعمل الطرق المضمنة JSON.parse() و JSON.stringify() في TypeScript كما في JavaScript، ولكن مع اختلافات مهمة في التصنيف.
// تحليل بسيط — ستكون النتيجة من النوع anyconst data: any = JSON.parse('{"name": "Alice", "age": 30}');
// من الأفضل تحديد النوع مباشرةinterface User { name: string; age: number;}
const user: User = JSON.parse('{"name": "Alice", "age": 30}') as User;console.log(user.name); // Aliceمن المهم أن نفهم: as User هو تحويل نوع (type assertion)، وليس تحققًا. إذا كان JSON يحتوي على بيانات غير صالحة، فلن يحذرك TypeScript من الخطأ. للعمل الآمن، نحتاج إلى التحقق من الصحة.
التحليل الآمن باستخدام Generics
لننشئ دالة عامة للتحليل الآمن لـ JSON مع التحقق من البنية:
function safeParse<T>(json: string, validator: (data: unknown) => data is T): T | null { try { const parsed: unknown = JSON.parse(json); if (validator(parsed)) { return parsed; } return null; } catch { return null; }}
// نحدد النوع ودالة التحققinterface Product { id: number; title: string; price: number;}
function isProduct(data: unknown): data is Product { if (typeof data !== 'object' || data === null) return false; const obj = data as Record<string, unknown>; return ( typeof obj.id === 'number' && typeof obj.title === 'string' && typeof obj.price === 'number' );}
const jsonString = '{"id": 1, "title": "Book", "price": 19.99}';const product = safeParse<Product>(jsonString, isProduct);if (product) { console.log(`المنتج: ${product.title}, السعر: ${product.price}`);} else { console.log('تنسيق JSON غير صحيح');}العمل مع الهياكل المتداخلة والمصفوفات
غالبًا ما تحتوي بيانات JSON الحقيقية على كائنات ومصفوفات متداخلة. لنلقِ نظرة على مثال لتصنيف بنية معقدة:
interface Order { id: string; customer: { name: string; email: string; }; items: Array<{ productId: number; quantity: number; }>; total: number;}
// نحلل ونتحقق من البنية فورًاfunction parseOrder(json: string): Order { const raw = JSON.parse(json); // تحقق بسيط if (!raw.id || !raw.customer || !Array.isArray(raw.items)) { throw new Error('بنية الطلب غير صالحة'); } return raw as Order;}
const orderJson = `{ "id": "ORD-001", "customer": {"name": "Bob", "email": "bob@example.com"}, "items": [{"productId": 42, "quantity": 2}], "total": 59.98}`;
try { const order = parseOrder(orderJson); console.log(`الطلب ${order.id} بقيمة ${order.total}`);} catch (e) { console.error('خطأ في التحليل:', e.message);}التسلسل باستخدام محولات مخصصة
أحيانًا نحتاج إلى التحكم في كيفية تحويل الكائنات إلى JSON. يسمح TypeScript بإنشاء مسلسلات مخصصة:
interface Config { host: string; port: number; timeout: number; // بالميلي ثانية}
function serializeConfig(config: Config): string { return JSON.stringify({ host: config.host, port: config.port, timeout: config.timeout / 1000 // تحويل إلى ثوانٍ }, null, 2); // تنسيق مع مسافات بادئة}
const myConfig: Config = { host: 'localhost'