يسرد نوع الكائن في TypeScript الخصائص التي يملكها الكائن ونوع كل منها: { name: string; age: number }. أضف ? لجعل خاصية اختيارية وreadonly لمنع إعادة إسنادها. اكتب النوع مضمّنًا، أو سمّه بـ type أو interface لإعادة استخدامه.
كتابة أنواع الكائنات
تُفصل الخصائص بـ ; أو , (كلاهما يعمل، و; الأسلوب المعتاد)، وفاصل السطر وحده يكفي. النوع المضمّن مناسب لمعامل يُستخدم مرة واحدة؛ ولكل ما يُستخدم مرتين، أعطه اسمًا.
// Inline, in a parameter
function area(rect: { width: number; height: number }): number {
return rect.width * rect.height;
}
// Named with a type alias
type Rect = { width: number; height: number };
// Named with an interface (the same shape)
interface RectShape {
width: number;
height: number;
}
يصف type وinterface أشكال الكائنات بالكفاءة نفسها. الفروق بينهما (دمج التصريحات وunion) مشروحة في صفحة interface مقابل type.
الوصول إلى خاصية لا يعلنها النوع خطأ ترجمة: point.z يعطي TS2339، Property 'z' does not exist on type '{ x: number; y: number; }'.
الخصائص الاختيارية
علامة ? بعد الاسم تسمح بترك الخاصية. قراءة خاصية اختيارية تعطي T | undefined، لذلك تجبرك TypeScript على معالجة حالة الغياب قبل استخدامها.
استدعاء دالة على خاصية اختيارية دون فحص خطأ: p.nickname.toUpperCase() يفشل بالخطأ TS18048، 'p.nickname' is possibly 'undefined'. استخدم optional chaining (p.nickname?.toUpperCase()) عندما تكون undefined نتيجة مقبولة.
prop?: T وprop: T | undefined ليسا الشيء نفسه. الأول يسمح بغياب المفتاح؛ والثاني يشترط وجود المفتاح، وإن كانت قيمته قد تكون undefined:
خصائص readonly
يمنع readonly إعادة إسناد الخاصية بعد إنشاء الكائن. إنه فحص وقت الترجمة فقط، وهو سطحي: الكائن أو المصفوفة المخزنة في خاصية readonly يمكن تغيير محتواها.
يُظهر الناتج الحدين معًا: تغيّر id فعلًا وقت التشغيل (لم يكن يعرف أنه readonly إلا المترجم)، وعُدّلت المصفوفة الداخلية. للمصفوفة للقراءة فقط استخدم readonly string[]؛ ولجعل كل الخصائص readonly دفعة واحدة، استخدم Readonly<Order>.
فحص الخصائص الزائدة
عندما تُسند كائنًا حرفيًا مباشرة إلى متغير له نوع أو تمرره مباشرة إلى معامل له نوع، ترفض TypeScript أي خاصية لا يعلنها النوع. الخصائص الإضافية في كائن حرفي جديد أخطاء إملائية في أغلب الأحيان.
index.ts(8,8): error TS2561: Object literal may only specify known properties, but 'colour' does not exist in type 'Options'. Did you mean to write 'color'?
رمز الخطأ TS2561 لأن المترجم وجد اسمًا قريبًا؛ أما الخاصية الإضافية التي ليس لها اسم مشابه فتعطي TS2353، Object literal may only specify known properties, and 'z' does not exist in type 'Point'. دون هذا الفحص كان الخطأ الإملائي سيُترجم، وستكون color هي undefined، وسيرسم البرنامج بالأسود بصمت. ينطبق الفحص على الكائنات الحرفية الجديدة فقط. الكائن الموجود أصلًا في متغير يمكن أن يحمل خصائص إضافية، لأن الأنواع في TypeScript بنيوية: القيمة تناسب النوع عندما تملك الخصائص المطلوبة على الأقل.
الكائنات المتداخلة والدوال
تتداخل أنواع الكائنات، ويمكنها وصف الدوال إما بصياغة method أو بخاصية نوعها دالة.
للأشكال العميقة أو المعاد استخدامها، سمِّ النوع الداخلي (type Address = { ... }) وأشر إليه، أو استخرجه من النوع الخارجي بـ indexed access، Company["address"]، كما تفعل الأسطر الأخيرة.
object مقابل {} مقابل Object
ثلاثة أنواع متشابهة في الاسم وتعني أشياء مختلفة:
| النوع | يقبل | يرفض |
|---|---|---|
object | أي قيمة غير بدائية: {} و[] والدوال ونسخ الأصناف | 5 و"a" وtrue وnull وundefined |
{} | أي قيمة ما عدا null وundefined، ومنها القيم البدائية | null وundefined |
Object | مثل {}، مع فحص أن الأعضاء المدمجة مثل toString تحتفظ بأنواع متوافقة | null وundefined |
{ x: number } | أي قيمة لها x رقمية | القيم التي لا تملك x |
لا يعني {} «كائنًا فارغًا»؛ بل يعني «ليس null ولا undefined». لقبول أي كائن بمفاتيح غير معروفة، استخدم Record<string, unknown>؛ ولخريطة من المفاتيح إلى القيم، استخدم index signature أو Record كما في صفحة القاموس. وفي أغلب الأحيان يكون الشكل المحدد أفضل من الثلاثة كلها.
الأسئلة الشائعة
كيف أعرّف نوع كائن في TypeScript؟
اسرد الخصائص وأنواعها بين أقواس معقوصة: { name: string; age: number }. يمكنك كتابته مضمّنًا في تعليق نوع، أو إعطاؤه اسمًا بـ type User = { ... } أو interface User { ... } وإعادة استخدامه. افصل بين الخصائص بـ ; أو ,.
كيف أجعل خاصية اختيارية في TypeScript؟
ضع ? بعد اسم الخاصية: { name: string; nickname?: string }. يمكن للكائن أن يترك nickname، وقراءتها تعطي string | undefined، لذلك يجب أن تتحقق منها أو توفر قيمة بديلة (user.nickname ?? user.name) قبل استخدامها كنص.
ما الفرق بين prop?: string و prop: string | undefined؟
prop?: string و prop: string | undefined؟مع prop?: string يمكن ترك المفتاح كليًا. ومع prop: string | undefined يكون المفتاح إلزاميًا، وإن كانت قيمته قد تكون undefined، لذلك {} خطأ ترجمة. وقراءة أي منهما تعطي string | undefined.
ما الفرق بين object و {} و Object في TypeScript؟
object يعني أي قيمة غير بدائية (كائنات ومصفوفات ودوال) ويرفض 5 أو "a". و{} يعني أي قيمة ما عدا null وundefined، ومنها القيم البدائية. وObject مطابق تقريبًا لـ {} لكنه يتحقق أيضًا من أن الدوال المدمجة مثل toString تحتفظ بأنواع متوافقة. استخدم object، أو الأفضل شكلًا محددًا، بدل {} أو Object.
لماذا تشتكي TypeScript من أن الكائن الحرفي لا يحدد إلا الخصائص المعروفة؟
هذا هو فحص الخصائص الزائدة: الخطأ TS2353، أو TS2561 عندما يستطيع المترجم اقتراح الخاصية التي قصدتها على الأرجح. عندما تُسند كائنًا حرفيًا جديدًا مباشرة إلى متغير أو معامل له نوع، تُعلَّم أي خاصية لا يعلنها النوع، لأنها غالبًا خطأ إملائي. أما إسناد كائن مخزن في متغير آخر فيتخطى الفحص، لأن الخصائص الإضافية مسموحة في الأنواع البنيوية.