TypeScript: برنامجك الأول بلغة TypeScript
آخر تحديث: 2026-08-26
الآن بعد أن انتهيت من التعرف على التثبيت والتكوين، حان الوقت لكتابة أول برنامج لك بلغة TypeScript — تابع خطوات سير العمل الكاملة في TypeScript، بدءًا من كتابة الكود وحتى تشغيله.
1. إنشاء ملف مشروع
في دليل المشروع الذي تم إنشاؤه في الدرس السابق، قم بإنشاء مجلد جديد باسم src/hello.ts:
my-project/
├── src/
│ └── hello.ts ← Create this file
├── tsconfig.json
└── package.json
أدخل الرمز التالي في hello.ts:
// First TypeScript Program
let username: string = "Charlie";
let age: number = 18;
function greet(name: string, userAge: number): string {
return name + " This year " + userAge + " years old";
}
console.log(greet(username, age));
يكمن الاختلاف الأكبر بين هذا الكود ولغة جافا سكريبت في أن كل متغير ومعلمة يتبعه توضيح النوع (: string، : number).
2. نظرة أولى على تعليقات الأنواع
تعد تعليقات الأنواع جوهر بناء جملة لغة TypeScript، وصيغتها بسيطة للغاية: اسم المتغير + فاصلة + النوع.
let Variable Name: Type = value;
(1) التعليقات التوضيحية المشتركة للأنواع الأساسية
let name: string = "Diana"; // String
let age: number = 20; // Numbers
let isStudent: boolean = true; // Boolean value
let score: number = 95.5; // Decimals are also number
let nothing: null = null; // null
let empty: undefined = undefined; // undefined
(2) تعليقات توضيحية لنوع الدالة
يجب أن تحدد الدوال جزأين: أنواع المعلمات وأنواع القيم المرجعة.
function Function Name(Parameters: Parameter Types): Return Type {
// Function Body
}
- نوع المعلمة: أضف
: typeبعد كل معلمة - نوع القيمة المرجعة: أضف
: typeبعد الأقواس التي تحتوي على المعلمات
▶ مثال: الدوال المزودة بتعليقات النوع
// Calculate the sum of two numbers
function add(a: number, b: number): number {
return a + b;
}
// Concatenating Strings
function joinWords(first: string, second: string): string {
return first + " " + second;
}
console.log(add(3, 5));
console.log(joinWords("Hello", "The World"));
الناتج:
8
Hello The World
void:function log(msg: string): void { console.log(msg); }
3. ترجمة كود TypeScript
بعد كتابة الملف .ts، يتعين عليك ترجمته إلى .js قبل أن تتمكن من تشغيله.
(1) ترجمة ملف واحد يدويًّا
tsc src/hello.ts
سيؤدي ذلك إلى إنشاء ملف باسم src/hello.js في نفس الدليل. افتحه، وسترى أن جميع تعليقات الأنواع قد اختفت:
// Compiled hello.js
var username = "Charlie";
var age = 18;
function greet(name, userAge) {
return name + " This year " + userAge + " years old";
}
console.log(greet(username, age));
هذا هو ما يُعرف بـ محو الأنواع في TypeScript — حيث لا تسري تعليقات الأنواع إلا في مرحلة التحويل البرمجي، ويكون كود JavaScript الناتج مطابقًا تقريبًا للكود المكتوب يدويًّا.
(2) قم بتجميع المشروع بأكمله باستخدام ملف tsconfig.json
إذا كان مشروعك يحتوي على tsconfig.json، فما عليك سوى تشغيل الأمر التالي في الدليل الجذري للمشروع:
tsc
سيقوم المُجمِّع بتجميع جميع ملفات .ts وتجميعها دفعة واحدة وفقًا للمدخلات rootDir وoutDir الموجودة في ملف التكوين.
▶ مثال: الترجمة والتشغيل
# Go to the project directory
cd my-project
# Compilation(According to tsconfig.json Layout)
tsc
# Run the compiled JS
node dist/hello.js
الناتج:
Charlie This year 18 years old
dist/hello.js، وليس src/hello.ts. تتمثل خطوات عملية تطوير TypeScript دائمًا في: كتابة ملف .ts → ترجمة → تشغيل ملف .js.
4. اكتشف قوة التحقق من أنواع البيانات
القيمة الأساسية لـ TypeScript — اكتشاف الأخطاء في مرحلة التحويل البرمجي. دعونا نكتب بعض الأكواد الخاطئة عن قصد ونرى كيف يكتشفها TypeScript.
(1) عدم تطابق الأنواع
let score: number = 90;
score = "Excellent"; // ❌ Error:You cannot convert the type"string"Assigned to Type"number"
يعمل هذا الكود «بشكل صحيح» في JavaScript، لكن تظهر المشاكل عند استخدام score في العمليات الحسابية لاحقًا. ويكتشف TypeScript هذا الخطأ مباشرةً في مرحلة التحويل البرمجي.
(2) نوع المعلمة غير صالح
function add(a: number, b: number): number {
return a + b;
}
add(3, "5"); // ❌ Error:Type"string"Parameters cannot be assigned to types"number"parameters
في JavaScript، تُرجع add(3, "5") القيمة "35" (تسلسل سلاسل)، وهو ما لا يمثل النتيجة التي تريدها على الأرجح. ويُعلمك TypeScript مسبقًا بأنك قمت بتمرير وسيطة خاطئة.
(3) استدعاء دالة غير موجودة
let name: string = "Charlie";
name.toFixed(2); // ❌ Error:Type"string"The property does not exist"toFixed"
toFixed هي دالة من النوع number، لكنها غير موجودة في string. ستُصدر لغة جافا سكريبت خطأً من النوع TypeError أثناء وقت التشغيل، لكن لغة TypeScript تلتقط هذا الخطأ أثناء وقت التحويل البرمجي.
▶ مثال: مقارنة بين الكشف عن الأخطاء في JavaScript و TypeScript
// ===== JavaScript Version:The problem wasn't discovered until runtime =====
let userAge = "25"; // String "25"
let nextYear = userAge + 1; // No errors will occur,But the result was "251" rather than 26
console.log(nextYear); // Output "251" —— That's not what we want.!
// ===== TypeScript Version:Intercepted at compile time =====
let userAge2: number = 25; // Clearly labeled as a number
let nextYear2: number = userAge2 + 1; // Correct:25 + 1 = 26
console.log(nextYear2); // Output 26
الناتج:
251
26
"25" + 1 على أنها "251" بدلاً من 26 — وهذه مأزق يقع فيه المبتدئون غالبًا. تستخدم TypeScript التحقق من الأنواع لمساعدتك على تجنب هذا النوع من المشكلات في مرحلة التحويل البرمجي.
5. tsc --watch: التجميع التلقائي
يُعد تشغيل tsc يدويًّا في كل مرة أقوم فيها بتعديل ملف .ts أمرًا شاقًّا للغاية. ويتيح وضع --watch (المُختصر بـ -w) للمُترجم مراقبة التغييرات التي تطرأ على الملفات والقيام بالترجمة فور حفظ الملف:
tsc --watch
أو حدد ملفًا واحدًا:
tsc src/hello.ts --watch
بمجرد تفعيل هذه الميزة، ستعرض المحطة الطرفية ما يلي:
[8:30:15 PM] Starting compilation in watch mode...
[8:30:15 PM] Found 0 errors. Watching for file changes.
في كل مرة تقوم فيها بحفظ الملف، يتم إعادة ترجمته تلقائيًا؛ ما عليك سوى التركيز على مخرجات node dist/xxx.js.
▶ مثال: سير العمل الكامل أثناء التطوير
# Terminal 1:Enable Automatic Compilation
tsc --watch
# Terminal 2:Run and Test
node dist/hello.js
# Edit src/hello.ts Run it again
node dist/hello.js
الناتج:
# Command executed successfully
ts-node لتشغيل ملف .ts مباشرةً (متخطيًا خطوة التجميع اليدوي): npm install -g ts-node، ثم ts-node src/hello.ts. هذه الأداة مريحة جدًّا للتعلم، لكن لا يزال عليك اتباع عملية التجميع في بيئة الإنتاج.
6. استدلال الأنواع — ما الذي يجعل TypeScript ذكيًّا للغاية
ربما لاحظت أن المتغيرات لا تتطلب جميعها تحديد النوع. فـ TypeScript ذكي بما يكفي لاستنتاج نوع المتغير تلقائيًا بناءً على قيمته الأولية:
let name = "Diana"; // TS Automatically inferred as string
let age = 20; // TS Automatically inferred as number
let isActive = true; // TS Automatically inferred as boolean
وهذا مكافئ تمامًا للكود التالي:
let name: string = "Diana";
let age: number = 20;
let isActive: boolean = true;
القاعدة بسيطة: عندما يتم توفير قيمة أولية، يمكن لـ TypeScript استنتاج النوع، لذا يمكنك حذف تعليق النوع؛ وعندما لا يتم توفير أي قيمة أولية، يجب عليك تحديد النوع صراحةً.
▶ مثال: متى يجب عليك تضمين تعليق النوع؟
// ✅ Has an initial value——Type can be inferred,Comments may be omitted
let message = "Hello";
let count = 0;
// ❌ No initial value——The type must be specified.,Otherwise TS The default is any
let userId: number; // Must be labeled
let userEmail: string; // Must be labeled
// ❌ Do not label = Implicit any(strict An error occurs in this mode)
let userId2; // ❌ Error:Variables implicitly have"any"Type
الناتج:
// Executed successfully
strict: true، ستؤدي المتغيرات التي تفتقر إلى قيم أولية أو تعليقات توضيحية للنوع إلى ظهور خطأ. وهذا أمر إيجابي — فهو يجبرك على تحديد نوع كل متغير بشكل صريح، مما يمنع ظهور any الغامضة في كل مكان.
❓ أسئلة شائعة
var بدلاً من let؟target في tsconfig.json. إذا قمت بتعيين target على ES5 (إصدار قديم جدًا)، فسيقوم المُجمِّع بتحويل let وconst إلى var لضمان التوافق. أما إذا قمت بتعيينه على ES2020 أو إصدار أحدث، فسيتم الحفاظ على let وconst. نوصي بتعيينه على ES2020.node dist/xxx.js يدويًّا في كل مرة أمرٌ شاقٌ للغاية. هل هناك طريقة أسهل؟npm install -g ts-node)، يمكنك ببساطة تشغيل ts-node src/xxx.ts لتخطي خطوة التجميع اليدوي. كما يدعم ملحق Code Runner الخاص بـ VS Code تنفيذ ملفات TS بنقرة واحدة. ومع ذلك، بالنسبة لمشاريع الإنتاج، ما زلنا نوصي باتباع عملية التجميع باستخدام tsc.📖 ملخص
- صيغة تعليق النوع:
let variableName: type = value؛ كما يمكن إضافة تعليقات على معلمات الدالة وقيم الإرجاع - يقوم TypeScript بمسح الأنواع بعد التحويل البرمجي، لذا فإن كود JavaScript الناتج لا يحتوي على معلومات عن الأنواع.
- القيمة الأساسية لـ TypeScript: الكشف عن أخطاء الأنواع في مرحلة التحويل البرمجي لمنع حدوث مشكلات في مرحلة التشغيل
tsc --watchالتجميع التلقائي،ts-nodeتشغيل ملفات TS مباشرةً- يُلغي استنتاج الأنواع الحاجة إلى تعيين القيم الأولية للمتغيرات يدويًّا، ولكن يجب تعيين قيم للمتغيرات التي لا تحتوي على قيم أولية.
- سيؤدي استخدام
anyضمنيًا في الوضع الصارم إلى ظهور خطأ، وهذا أمر جيد — فهو يجبرك على تحديد النوع بوضوح.
📝 تمارين
- تمرين أساسي (مستوى الصعوبة ⭐): أنشئ
src/hello.ts، وحدد ثلاثة متغيرات مع توضيح أنواعها (سلسلة، عدد، منطقية)، وقم بترجمة البرنامج وتشغيله، ثم استخدمconsole.logلعرض قيمها. - مشكلة متقدمة (درجة الصعوبة ⭐⭐): اكتب دالة مُعلَّمة بالأنواع
calculateArea(width: number, height: number): numberتُحسب مساحة المستطيل. قم عمدًا بتمرير معلمة من نوع سلسلة إليها، ولاحظ رسالة خطأ الترجمة في TypeScript، ثم قم بإصلاح الخطأ. - التحدي (الصعوبة: ⭐⭐⭐): قارن بين كيفية تعامل كل من JavaScript و TypeScript مع نفس مجموعة رموز الأخطاء — اكتب جزءًا من كود JavaScript يحتوي على ثلاثة أنواع من الأخطاء (معاملة سلسلة نصية كرقم، واستدعاء دالة غير موجودة، والوصول إلى خاصية غير مُعرَّفة)، ثم أعد كتابته بلغة TypeScript، مع الإشارة إلى السطر الذي يُبلغ فيه TypeScript عن كل خطأ.