استكشف توقيعات التأكيد في TypeScript لفرض التحقق من الأنواع وقت التشغيل، مما يعزز موثوقية الكود ويمنع الأخطاء غير المتوقعة. تعلم أمثلة عملية وأفضل الممارسات.
توقيعات التأكيد في TypeScript: التحقق من الأنواع في وقت التشغيل لكود برمجي متين
توفر TypeScript فحصًا ممتازًا للأنواع الثابتة أثناء التطوير، مما يكتشف الأخطاء المحتملة قبل وقت التشغيل. ومع ذلك، تحتاج أحيانًا إلى ضمان أمان الأنواع في وقت التشغيل. وهنا يأتي دور توقيعات التأكيد. فهي تسمح لك بتعريف دوال لا تكتفي بالتحقق من نوع القيمة فحسب، بل تُعلِم TypeScript أيضًا بأن نوع القيمة قد تم تضييقه بناءً على نتيجة الفحص.
ما هي توقيعات التأكيد؟
توقيع التأكيد هو نوع خاص من توقيعات الدوال في TypeScript يستخدم الكلمة المفتاحية asserts
. يخبر هذا التوقيع TypeScript بأنه إذا عادت الدالة دون إلقاء خطأ، فإن شرطًا محددًا حول نوع الوسيط (argument) مضمون بأنه صحيح. هذا يسمح لك بتنقيح الأنواع بطريقة يفهمها المترجم، حتى عندما لا يستطيع استنتاج النوع تلقائيًا بناءً على الكود.
الصيغة الأساسية هي:
function assertsCondition(argument: Type): asserts argument is NarrowedType {
// ... implementation that checks the condition and throws if it's false ...
}
assertsCondition
: اسم الدالة الخاصة بك.argument: Type
: الوسيط الذي تريد التحقق من نوعه.asserts argument is NarrowedType
: هذا هو توقيع التأكيد. يخبر TypeScript بأنه إذا عادتassertsCondition(argument)
دون إلقاء خطأ، فيمكن لـ TypeScript معاملةargument
على أنه من النوعNarrowedType
.
لماذا نستخدم توقيعات التأكيد؟
توفر توقيعات التأكيد عدة فوائد:
- التحقق من الأنواع في وقت التشغيل: تمكّنك من التحقق من نوع القيمة في وقت التشغيل، مما يمنع الأخطاء غير المتوقعة التي قد تنشأ عن بيانات غير صحيحة.
- تحسين أمان الكود: من خلال فرض قيود النوع في وقت التشغيل، يمكنك تقليل مخاطر الأخطاء البرمجية وتحسين الموثوقية العامة للكود الخاص بك.
- تضييق النوع: تسمح توقيعات التأكيد لـ TypeScript بتضييق نوع المتغير بناءً على نتيجة فحص وقت التشغيل، مما يتيح فحص أنواع أكثر دقة في الكود اللاحق.
- تعزيز قابلية قراءة الكود: تجعل الكود الخاص بك أكثر وضوحًا بشأن الأنواع المتوقعة، مما يسهل فهمه وصيانته.
أمثلة عملية
مثال 1: التحقق من وجود سلسلة نصية (String)
لنقم بإنشاء دالة تؤكد أن القيمة هي سلسلة نصية. إذا لم تكن كذلك، فإنها تطلق خطأ.
function assertIsString(value: any): asserts value is string {
if (typeof value !== 'string') {
throw new Error(`Expected a string, but received ${typeof value}`);
}
}
function processString(input: any) {
assertIsString(input);
// TypeScript now knows that 'input' is a string
console.log(input.toUpperCase());
}
processString("hello"); // Works fine
// processString(123); // Throws an error at runtime
في هذا المثال، تتحقق assertIsString
مما إذا كانت القيمة المدخلة سلسلة نصية. إذا لم تكن كذلك، فإنها تطلق خطأ. إذا عادت الدالة دون إطلاق خطأ، فإن TypeScript يعرف أن input
هي سلسلة نصية، مما يسمح لك باستدعاء دوال السلاسل النصية مثل toUpperCase()
بأمان.
مثال 2: التحقق من بنية كائن محددة
لنفترض أنك تعمل مع بيانات تم جلبها من واجهة برمجة تطبيقات (API) وتريد التأكد من أنها تتوافق مع بنية كائن محددة قبل معالجتها. لنقل أنك تتوقع كائنًا يحتوي على خاصيتي name
(سلسلة نصية) و age
(رقم).
interface Person {
name: string;
age: number;
}
function assertIsPerson(value: any): asserts value is Person {
if (typeof value !== 'object' || value === null) {
throw new Error(`Expected an object, but received ${typeof value}`);
}
if (!('name' in value) || typeof value.name !== 'string') {
throw new Error(`Expected a string 'name' property`);
}
if (!('age' in value) || typeof value.age !== 'number') {
throw new Error(`Expected a number 'age' property`);
}
}
function processPerson(data: any) {
assertIsPerson(data);
// TypeScript now knows that 'data' is a Person
console.log(`Name: ${data.name}, Age: ${data.age}`);
}
processPerson({ name: "Alice", age: 30 }); // Works fine
// processPerson({ name: "Bob", age: "30" }); // Throws an error at runtime
// processPerson({ name: "Charlie" }); // Throws an error at runtime
هنا، تتحقق assertIsPerson
مما إذا كانت القيمة المدخلة كائنًا يحتوي على الخصائص والأنواع المطلوبة. إذا فشل أي فحص، فإنها تطلق خطأ. وإلا، فإن TypeScript يعامل data
ككائن من نوع Person
.
مثال 3: التحقق من قيمة Enum محددة
لنتأمل تعدادًا (enum) يمثل حالات مختلفة للطلب.
enum OrderStatus {
PENDING = "PENDING",
PROCESSING = "PROCESSING",
SHIPPED = "SHIPPED",
DELIVERED = "DELIVERED",
}
function assertIsOrderStatus(value: any): asserts value is OrderStatus {
if (!Object.values(OrderStatus).includes(value)) {
throw new Error(`Expected OrderStatus, but received ${value}`);
}
}
function processOrder(status: any) {
assertIsOrderStatus(status);
// TypeScript now knows that 'status' is an OrderStatus
console.log(`Order status: ${status}`);
}
processOrder(OrderStatus.SHIPPED); // Works fine
// processOrder("CANCELLED"); // Throws an error at runtime
في هذا المثال، تضمن assertIsOrderStatus
أن القيمة المدخلة هي قيمة صالحة من تعداد OrderStatus
. إذا لم تكن كذلك، فإنها تطلق خطأ. هذا يساعد على منع معالجة حالات الطلب غير الصالحة.
مثال 4: استخدام مُسنَدات النوع (type predicates) مع دوال التأكيد
من الممكن الجمع بين مُسنَدات النوع ودوال التأكيد لمزيد من المرونة.
function isString(value: any): value is string {
return typeof value === 'string';
}
function assertString(value: any): asserts value is string {
if (!isString(value)) {
throw new Error(`Expected a string, but received ${typeof value}`);
}
}
function processValue(input: any) {
assertString(input);
console.log(input.toUpperCase());
}
processValue("TypeScript"); // Works
// processValue(123); // Throws
أفضل الممارسات
- اجعل التأكيدات موجزة: ركز على التحقق من الخصائص أو الشروط الأساسية اللازمة لعمل الكود بشكل صحيح. تجنب التأكيدات المعقدة بشكل مفرط والتي قد تبطئ تطبيقك.
- قدم رسائل خطأ واضحة: قم بتضمين رسائل خطأ غنية بالمعلومات تساعد المطورين على تحديد سبب الخطأ بسرعة وكيفية إصلاحه. استخدم لغة محددة توجه المستخدم. على سبيل المثال، بدلاً من قول "بيانات غير صالحة"، قل "من المتوقع وجود كائن بخاصيتي 'name' و 'age'."
- استخدم مُسنَدات النوع (Type Predicates) للفحوصات المعقدة: إذا كان منطق التحقق لديك معقدًا، ففكر في استخدام مُسنَدات النوع لتغليف منطق فحص النوع وتحسين قابلية قراءة الكود.
- ضع في اعتبارك الآثار المترتبة على الأداء: يضيف التحقق من النوع في وقت التشغيل عبئًا على تطبيقك. استخدم توقيعات التأكيد بحكمة وفقط عند الضرورة. يجب تفضيل التحقق من النوع الثابت حيثما أمكن ذلك.
- تعامل مع الأخطاء بأناقة: تأكد من أن تطبيقك يتعامل مع الأخطاء التي تطلقها دوال التأكيد بأناقة، مما يمنع الأعطال ويوفر تجربة مستخدم جيدة. فكر في تغليف الكود الذي قد يفشل في كتل try-catch.
- وثّق تأكيداتك: وثّق بوضوح الغرض وسلوك دوال التأكيد الخاصة بك، موضحًا الشروط التي تتحقق منها والأنواع المتوقعة. سيساعد هذا المطورين الآخرين على فهم واستخدام الكود الخاص بك بشكل صحيح.
حالات الاستخدام عبر مختلف الصناعات
يمكن أن تكون توقيعات التأكيد مفيدة في مختلف الصناعات:
- التجارة الإلكترونية: التحقق من صحة مدخلات المستخدم أثناء الدفع لضمان صحة عناوين الشحن ومعلومات الدفع وتفاصيل الطلب.
- التمويل: التحقق من البيانات المالية من مصادر خارجية، مثل أسعار الأسهم أو أسعار صرف العملات، قبل استخدامها في الحسابات أو التقارير.
- الرعاية الصحية: ضمان توافق بيانات المرضى مع تنسيقات ومعايير محددة، مثل السجلات الطبية أو نتائج المختبرات.
- التصنيع: التحقق من صحة البيانات من أجهزة الاستشعار والآلات لضمان سير عمليات الإنتاج بسلاسة وكفاءة.
- الخدمات اللوجستية: التحقق من دقة واكتمال بيانات الشحن، مثل أرقام التتبع وعناوين التسليم.
بدائل لتوقيعات التأكيد
بينما تعد توقيعات التأكيد أداة قوية، هناك أيضًا طرق أخرى للتحقق من النوع في وقت التشغيل في TypeScript:
- حراس النوع (Type Guards): هي دوال تعيد قيمة منطقية (boolean) تشير إلى ما إذا كانت القيمة من نوع معين. يمكن استخدامها لتضييق نوع المتغير داخل كتلة شرطية. ومع ذلك، على عكس توقيعات التأكيد، فإنها لا تطلق أخطاء عند فشل فحص النوع.
- مكتبات التحقق من الأنواع في وقت التشغيل: توفر مكتبات مثل
io-ts
وzod
وyup
إمكانيات شاملة للتحقق من الأنواع في وقت التشغيل، بما في ذلك التحقق من صحة المخطط (schema) وتحويل البيانات. يمكن أن تكون هذه المكتبات مفيدة بشكل خاص عند التعامل مع هياكل بيانات معقدة أو واجهات برمجة تطبيقات خارجية.
الخاتمة
توفر توقيعات التأكيد في TypeScript آلية قوية لفرض التحقق من الأنواع في وقت التشغيل، مما يعزز موثوقية الكود ويمنع الأخطاء غير المتوقعة. من خلال تعريف دوال تؤكد نوع القيمة، يمكنك تحسين أمان الأنواع، وتضييق الأنواع، وجعل الكود الخاص بك أكثر وضوحًا وقابلية للصيانة. على الرغم من وجود بدائل، تقدم توقيعات التأكيد طريقة خفيفة الوزن وفعالة لإضافة فحوصات النوع في وقت التشغيل إلى مشاريع TypeScript الخاصة بك. باتباع أفضل الممارسات والنظر بعناية في الآثار المترتبة على الأداء، يمكنك الاستفادة من توقيعات التأكيد لبناء تطبيقات أكثر قوة وموثوقية.
تذكر أن توقيعات التأكيد تكون أكثر فعالية عند استخدامها جنبًا إلى جنب مع ميزات التحقق من الأنواع الثابتة في TypeScript. يجب استخدامها لتكملة، وليس استبدال، التحقق من النوع الثابت. من خلال الجمع بين التحقق من الأنواع الثابتة وفي وقت التشغيل، يمكنك تحقيق مستوى عالٍ من أمان الكود ومنع العديد من الأخطاء الشائعة.