JSON إلى TypeScript
أنشئ تعريفات interface في TypeScript من JSON
نبذة عن JSON إلى TypeScript
تقرأ أداة «JSON إلى TypeScript» عينة JSON وتكتب تعريفات interface في TypeScript التي تصفها، باستخدام محرك quicktype-core في متصفحك. يصبح كل كائن متداخل interface مستقلا مصدّرا، ويفحص كل عنصر في المصفوفة: المفتاح الغائب عن بعض العناصر يأخذ علامة استفهام، والقيمة التي تكون null أحيانا يكتب نوعها مع null في نوع اتحاد (union). وتكتب المفاتيح التي ليست أسماء معرّفات صالحة (identifiers)، مثل first-name، بين علامتي اقتباس. لا تنشئ الأداة إلا الأنواع: لا classes، ولا تحقق أثناء التشغيل، ولا أنواع enum أو تواريخ أو UUID تستنتج من القيم النصية.
مثال
سجلا مستخدمين من API: قيمة lastLogin هي null في الثاني، وaddress موجود في الأول فقط، وtags فارغة في الثاني، وmanager-id ليس اسم معرّف صالحا. الإخراج أدناه هو بالضبط ما يكتبه «تحويل».
إدخال JSON
[{"id": 101, "email": "ada@example.com", "role": "admin",
"lastLogin": "2026-10-01T08:30:00Z",
"address": {"city": "London", "zip": "N1 9GU"},
"tags": ["beta"], "manager-id": null},
{"id": 102, "email": "lin@example.com", "role": "editor",
"lastLogin": null, "tags": [], "manager-id": 101}]إخراج TypeScript
export interface Root {
id: number;
email: string;
role: string;
lastLogin: null | string;
address?: Address;
tags: string[];
"manager-id": number | null;
}
export interface Address {
city: string;
zip: string;
}كيفية إنشاء تعريفات interface في TypeScript من JSON
- 1الصق كائن JSON، أو مصفوفة من عدة كائنات تمثل بياناتك، في «إدخال JSON».
- 2انقر على «تحويل»؛ تجلب الصفحة المحرك عند النقرة الأولى، ثم تملأ تعريفات interface مربع «إخراج TypeScript».
- 3قارن المفاتيح الاختيارية وأنواع الاتحاد مع null بالبيانات التي سيتلقاها الكود فعلا.
- 4انقر على «نسخ»، أو على «تنزيل» لحفظ الكود في الملف «types.ts».
الصيغ والحدود
- الإدخال
- نص JSON: كائن، أو مصفوفة كائنات تدمج عناصرها؛ أما مصفوفة القيم البسيطة فتعطي رسالة بدلا من الكود
- الإخراج
- تعريفات interface مصدّرة في TypeScript، واحد لكل كائن متداخل، تحفظ باسم types.ts
- المفاتيح الاختيارية
- علامة استفهام عندما يغيب مفتاح عن بعض عناصر المصفوفة؛ وnull في نوع اتحاد عندما تكون القيمة null
- ما لا تنشئه الأداة
- classes، والتحقق أثناء التشغيل، وأنواع enum والتاريخ وUUID (تبقى السلاسل النصية من النوع string)
استخدامات شائعة
- كتابة أنواع استجابة REST API
- ينسخ مطور الواجهة الأمامية استجابة GET /users من تبويب الشبكة (Network) في المتصفح، ويلصق المصفوفة كاملة، فيحصل على interface باسم Root يصف مستخدما واحدا، وعلى interface لكل كائن متداخل، لكتابة نوع نتيجة استدعاء fetch.
- وصف ملف إعدادات
- يصبح ملف JSON لمفاتيح تفعيل الميزات (feature flags) أو لإعدادات التطبيق تعريف interface، فيكمل المحرر مفاتيحه تلقائيا ويشير إلى المفتاح المكتوب خطأ في الكود الذي يقرؤها.
- العثور على الحقول التي يغفلها مصدر البيانات
- لصق 50 سجلا من سجلات webhook أو من بيانات مصدّرة يبين، بعلامات الاستفهام وأنواع الاتحاد مع null، المفاتيح التي تغيب عن بعض السجلات والمفاتيح التي تكون null أحيانا، قبل أن يفترض الكود أنها موجودة دائما.
أي أداة تختار
- منسق JSON: عندما يرد «تحويل» برسالة «نص JSON غير صالح»، تعرض هذه الأداة السطر الذي فيه الخطأ مع علامة ^ تحت موضع المشكلة، فتصحح العينة وتلصقها هنا من جديد.
- JSON إلى struct في Go: محرك quicktype نفسه ودمج عناصر المصفوفة نفسه، لكن الكود يكتب على شكل struct في Go مع وسوم json وحقول int64 أو float64 بدلا من تعريفات interface في TypeScript.
- TypeScript إلى JavaScript: المهمة المعاكسة: تحذف تعليقات الأنواع (type annotations) وتعريفات interface من كود TypeScript المصدري لتترك JavaScript عاديا، ولا تقرأ JSON.
أين يعالج نص JSON الخاص بك
تنشأ تعريفات interface في متصفحك: تجلب الصفحة محرك quicktype عند نقرتك الأولى، ولا يرفع نص JSON الخاص بك، ولا كود TypeScript الناتج عنه. إذا ظهرت رسالة خطأ، ترسل نسخة مختصرة من هذه الرسالة، بعد حذف النص المقتبس والأرقام الطويلة والعناوين منها، إلى سجل الأخطاء لدينا مع اسم الأداة واسم متصفحك وإصداره، حتى يمكن إصلاح الأداة.
الأسئلة الشائعة
هل تكتشف الأداة الحقول الاختيارية؟
نعم، عندما تلصق مصفوفة. تدمج كل العناصر: المفتاح الغائب عن بعضها يكتب مع علامة استفهام، والمفتاح الذي يكون null في بعضها يضاف null إلى نوعه، مثل null | string. أما مع كائن واحد، فكل المفاتيح التي يحتويها إلزامية.
كيف تكتب أنواع الكائنات والمصفوفات المتداخلة؟
يصبح كل كائن متداخل interface مصدّرا مستقلا يحمل اسم مفتاحه، مثل Team للمفتاح team، وتصبح مصفوفة الكائنات مصفوفة من هذا النوع. وتصبح مصفوفات السلاسل النصية أو الأرقام string[] أو number[]. والشجرة التي تكرر شكلها، مثل {"name": "a", "children": [{"name": "b", "children": []}]}، تعطي children: Root[] بدلا من سلسلة لا تنتهي من تعريفات interface.
ماذا يحدث للمفاتيح التي تحتوي على شرطات أو مسافات؟
تحتفظ بكتابتها الدقيقة كأسماء خصائص بين علامتي اقتباس، وهذا صالح في TypeScript، فيطابق تعريف interface نص JSON دون أي إعادة تسمية. أما المفاتيح التي هي أسماء معرّفات صالحة، مثل nickname، فتكتب دون علامات اقتباس.
هل يمكنني حفظ النتيجة في ملف .ts؟
نعم. بعد التحويل، يظهر تحت الإخراج سطر باسم types.ts فيه زر «تنزيل»؛ وعلى iPhone وiPad يضاف بجانبه زر «حفظ أو مشاركة». ويضع «نسخ» الكود نفسه في الحافظة.
ما النوع الذي يأخذه حقل تختلط قيمه بين أرقام وسلاسل نصية؟
نوع اتحاد يضم كل الأنواع الموجودة. [{"a": 1}, {"a": "x"}] يعطي a: number | string، والمصفوفة التي تحتوي على 1 و"a" وtrue يكون نوعها Array<boolean | number | string>.
ماذا تصبح المصفوفة الفارغة؟
تصبح unknown[]، لأن العينة لا تبين شيئا عن عناصرها. الصق سجلات تحتوي فيها هذه المصفوفة على عنصر واحد على الأقل، فيصبح النوع المدمج string[] أو number[] أو مصفوفة من interface.
هل يمكنني تحديد اسم الجذر أو الحصول على أسماء بديلة للأنواع (type aliases) بدلا من تعريفات interface؟
لا. يسمى interface الأعلى دائما Root، ويكتب كل شكل على صورة interface مصدّر. أعد تسمية Root في محررك، وغيّر interface إلى type بنفسك إذا كان مشروعك يفضل الأسماء البديلة.
ماذا لو اشترك كائنان متداخلان في اسم المفتاح نفسه دون أن تكون لهما الحقول نفسها؟
يأخذ كل شكل تعريف interface خاصا به، يسبق اسمه اسم الكائن الأب: المفتاح address تحت user وآخر تحت company يصبحان UserAddress وCompanyAddress، فلا يحل أحدهما محل الآخر.
هل من الآمن كتابة نوع المعرّفات الرقمية الطويلة على أنه number؟
ليس دائما. لا يحفظ JavaScript الأعداد الصحيحة بدقة إلا حتى 9,007,199,254,740,991، وكل رقم في JSON يكتب نوعه number هنا. عندما يحتوي JSON على عدد صحيح يتجاوز ذلك، يذكر تعليق في أعلى الإخراج عددها: فالدالة JSON.parse تقربها، لذا أبق هذه المعرّفات سلاسل نصية في API أو اقرأها بنوع bigint.
لماذا يشترك مفتاحان مختلفان في interface واحد باسم غريب؟
تدمج الكائنات التي لها الحقول والأنواع نفسها تماما في interface واحد، يسمى من المفاتيح التي تحملها. {"home": {"city": "x", "zip": "1"}, "work": {"city": "y", "zip": "2"}} يعطي home: Home وwork: Home؛ وbilling وshipping بالحقول نفسها يشتركان في interface اسمه Ing، وهو المقطع الأخير المشترك بين الاسمين. الشكل صحيح: أعد تسمية interface في محررك.
متى يصبح الكائن { [key: string]: T } بدلا من interface؟
عندما تبدو مفاتيحه بيانات لا أسماء حقول، وتكون كل قيمه من نوع واحد. {"byId": {"1": {...}, "2": {...}}} يعطي byId: { [key: string]: ByID }، وأسعار الصرف بالمفاتيح USD وEUR وGBP وJPY تعطي { [key: string]: number }. ومع USD وEUR وGBP فقط، أو مع مفاتيح هي كلمات مثل red وgreen وblue، يبقى كل مفتاح حقلا مسمى. هذه قاعدة تقديرية من المحرك، لذا تحقق من الكائنات التي مفاتيحها معرّفات أو رموز.
لماذا لا تعطي مصفوفة السلاسل النصية أو الأرقام أي interface؟
المصفوفة في المستوى الأعلى التي لا تحتوي إلا على قيم بسيطة، مثل ["a", "b"] أو [1, 2, 3] أو [] أو [[1]]، ليس فيها كائن لوصفه، لذا لا يكتب المحرك أي كود وتعرض الصفحة رسالة بدلا منه. ضع المصفوفة داخل كائن: {"items": ["a", "b"]} يعطي items: string[].
لماذا يكتب نوع تاريخ ISO على أنه string لا Date؟
لأن JSON.parse يعيد "2026-10-01T08:30:00Z" سلسلة نصية لا كائن Date. وتعريف interface يقول Date سيسمح للكود باستدعاء getTime() على قيمة ما زالت نصا أثناء التشغيل. وينطبق الأمر نفسه على UUID والأرقام المكتوبة بين علامتي اقتباس مثل "42": يبقى نوعها string حتى يحولها الكود.
هل تتحقق الأداة من أن البيانات تطابق تعريفات interface فعلا؟
لا. تحذف تعريفات interface في TypeScript عند ترجمة الكود (compile)، فهي تصف البيانات المتوقعة دون التحقق مما يصل. لا يحتوي الإخراج على كود تحقق ولا على مخطط Zod؛ استخدمه شكلا تتبعه عندما تكتب واحدا.
نصائح وحيل
- ✓أعد تسمية interface المسمى Root بعد لصقه في مشروعك؛ فالاسم يأتي من الأداة لا من بياناتك.
- ✓إذا كانت النتيجة رسالة «نص JSON غير صالح»، فافتح النص نفسه في أداة «منسق JSON»، التي تشير إلى سطر الخطأ وعموده.