مقدمة
تطورت JavaScript كثيراً منذ ES2015. الكود الحديث أقصر وأوضح وأقل أخطاءً. وTypeScript تضيف فوقها نظام أنواع يُفحص قبل التشغيل، فتكتشف أخطاء كاملة الفئة مبكراً. هذا الدرس يجمع ما ستستخدمه يومياً.
أهداف التعلم
- استخدام
constوletوالدوال السهمية والتفكيك والقوالب النصية. - فهم
async/awaitومعالجة أخطاء الوعود. - استخدام عوامل
?.و??. - كتابة أنواع TypeScript أساسية وأنواع الاتحاد.
1. const أولاً
const users = []; // لا يمكن إعادة الإسناد، لكن يمكن تعديل المصفوفة
let attempts = 0; // للقيم التي تتغير فعلاً
تجنب var: نطاقها الدالة لا الكتلة، وتسبب أخطاء غريبة داخل الحلقات.
2. التفكيك والقيم الافتراضية والانتشار
const user = { name: 'سارة', role: 'member', settings: { theme: 'dark' } };
const { name, settings: { theme = 'light' } = {} } = user;
function createPost({ title, tags = [], draft = false }) {
return { title, tags: [...tags, 'عرب-كود'], draft };
}
const updated = { ...user, role: 'moderator' }; // نسخة جديدة دون تعديل الأصل
3. ?. و??
const city = user.profile?.address?.city ?? 'غير محدد';
?. يتوقف بأمان إن كانت القيمة null أو undefined، و?? يعطي قيمة بديلة فقط لـ null/undefined؛ بخلاف || الذي يستبدل أيضاً 0 و"" وfalse:
const pageSize = 0;
pageSize || 20; // 20 (غالباً خطأ)
pageSize ?? 20; // 0
4. async/await ومعالجة الأخطاء
async function loadTopics() {
const res = await fetch('/api/topics?page=1');
if (!res.ok) throw new Error(`فشل الطلب: ${res.status}`);
return res.json();
}
try {
const topics = await loadTopics();
console.log(topics.length);
} catch (err) {
console.error('تعذر التحميل', err);
}
fetch لا يرمي خطأ عند 404 أو 500 — يجب فحص res.ok بنفسك. ولتنفيذ طلبات مستقلة بالتوازي:
const [topics, codes] = await Promise.all([loadTopics(), loadCodes()]);
5. TypeScript: الأنواع الأساسية
type Role = 'member' | 'moderator' | 'admin';
interface User {
id: string;
name: string;
role: Role;
bio?: string; // اختياري
}
function canModerate(user: User): boolean {
return user.role === 'moderator' || user.role === 'admin';
}
canModerate({ id: '1', name: 'أحمد', role: 'owner' });
// خطأ وقت الترجمة: '"owner"' غير قابل للإسناد إلى النوع 'Role'
نوع الاتحاد 'member' | 'moderator' | 'admin' يمنع الأخطاء الإملائية ويجعل المحرر يقترح القيم الصحيحة.
6. تضييق الأنواع
type Result = { ok: true; data: string[] } | { ok: false; error: string };
function show(r: Result) {
if (r.ok) {
console.log(r.data.length); // هنا يعرف TypeScript أن data موجودة
} else {
console.error(r.error);
}
}
هذا النمط (الاتحاد المميَّز) يجبرك على معالجة حالة الفشل.
7. لا تثق بالبيانات القادمة من الشبكة
أنواع TypeScript تختفي وقت التشغيل. ما يأتي من API أو نموذج قد لا يطابق النوع الذي كتبته. تحقق منه بمكتبة مثل Zod:
import { z } from 'zod';
const TopicSchema = z.object({ id: z.string(), title: z.string().min(1) });
const topic = TopicSchema.parse(await res.json()); // يرمي خطأ واضحاً إن لم يطابق
تمرين عملي
- حوّل دالة قديمة مكتوبة بـ
varو.then()إلىconstوasync/await. - أضف TypeScript إلى ملف واحد وشغّل
npx tsc --noEmit --strict، وأصلح ما يظهر. - اكتب نوع
ApiResponseكاتحاد مميَّز واستخدمه في دالة تعرض النتيجة أو الخطأ.
أخطاء شائعة
- نسيان
awaitفتحصل علىPromiseبدل القيمة. - استخدام
anyللهروب من الأخطاء؛ استخدمunknownثم ضيّق النوع. - الاعتقاد أن TypeScript يحمي من البيانات الخارجية وقت التشغيل.
forEachمعasyncلا ينتظر؛ استخدمfor...ofأوPromise.all.
الخلاصة
const، التفكيك، ?. و??، وasync/await تجعل JavaScript أوضح. TypeScript يضيف شبكة أمان وقت التطوير، ومع التحقق وقت التشغيل للبيانات الخارجية تحصل على كود موثوق.
مصادر مقترحة
- كتاب The Modern JavaScript Tutorial (javascript.info).
- دليل TypeScript الرسمي: «The TypeScript Handbook».
- توثيق Zod.