TypeScript: المصفوفات والتوبلات في TypeScript

آخر تحديث: 2026-08-26

تعد المصفوفات والتوبلات أكثر أنواع المجموعات استخدامًا في TypeScript — فالمصفوفة هي «مجموعة من القيم من نفس النوع»، في حين أن التوبلة هي نوع خاص من المصفوفات «ذو طول ثابت وأنواع محددة لكل عنصر».

1. أنواع المصفوفات

(1) صيغتان للتعليقات التوضيحية

توفر لغة TypeScript طريقتين متكافئتين لكتابة أنواع المصفوفات:

TYPESCRIPT
// Method 1:Type + square brackets(Recommendations,More intuitive)
let numbers: number[] = [1, 2, 3, 4, 5];
let names: string[] = ["Charlie", "Diana", "Eric"];

// Method 2:Generic Arrays(Commonly used in generic scenarios)
let scores: Array<number> = [90, 85, 95];
let items: Array<string> = ["a", "b", "c"];
📌 توصية: استخدم صيغة type[] في أعمال التطوير اليومية — فهي أكثر إيجازًا. أما الصيغة العامة Array<T> فهي أوضح عند التعامل مع أنواع معينة معقدة أو عند استخدامها مع الدوال العامة.

(2) استنتاج نوع المصفوفة

TYPESCRIPT
let arr1 = [1, 2, 3];           // Inferred as number[]
let arr2 = ["a", "b", "c"];     // Inferred as string[]
let arr3 = [1, "hello", true];  // Inferred as (number | string | boolean)[]
let arr4 = [];                  // Inferred as any[](Danger!)
🔥 خطأ شائع: يتم استنتاج أن المصفوفة الفارغة [] هي any[]، ولن تؤدي عمليات التعيين اللاحقة ذات الأنواع المختلفة إلى حدوث خطأ. في الوضع الصارم، يُنصح بتسميتها صراحةً بـ let arr4: number[] = [].

(3) المصفوفات متعددة الأبعاد

TYPESCRIPT
let matrix: number[][] = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

// Accessing Elements
console.log(matrix[0][1]);  // 2

// Three-dimensional array
let cube: number[][][] = [[[1]]];

▶ مثال: العمليات الأساسية على المصفوفات

TYPESCRIPT
let fruits: string[] = ["Apple", "Banana", "Orange"];

// Add an element
fruits.push("Grapes");          // Add at the end
fruits.unshift("Strawberries");       // Add at the beginning

// Delete Element
let last = fruits.pop();      // Delete the end,Back "Grapes"
let first = fruits.shift();   // Delete the beginning,Back "Strawberries"

// Search
let index = fruits.indexOf("Banana");  // 0(The strawberries and grapes were removed.,The banana came in first)

// Iterate
fruits.forEach((fruit, i) => {
  console.log(`${i}: ${fruit}`);
});
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
0: Banana
1: Orange


2. المصفوفات للقراءة فقط

لا يمكن تعديل المصفوفات المخصصة للقراءة فقط — فلا يُسمح بإضافة عناصر إليها أو حذفها أو تعديلها:

(1) المُعدِّل «readonly»

TYPESCRIPT
let readonlyArr: readonly number[] = [1, 2, 3];

// readonlyArr[0] = 10;     // ❌ Read-only,Cannot be modified
// readonlyArr.push(4);     // ❌ Read-only,Cannot be added
// readonlyArr.length = 0;  // ❌ Read-only,The length cannot be changed

let normalArr: number[] = [1, 2, 3];
readonlyArr = normalArr;    // ✅ A regular array can be assigned to a read-only array
// normalArr = readonlyArr; // ❌ A read-only array cannot be assigned to a regular array.

(2) ReadonlyArray العام

TYPESCRIPT
let readonlyArr2: ReadonlyArray<string> = ["a", "b", "c"];
// and readonly string[] Equivalent
💡 الغرض: إن استخدام مصفوفة للقراءة فقط كمعلمة للدالة يُوضح للمستدعي بشكل واضح أن «هذه الدالة لن تُعدِّل مصفوفتك»:

TYPESCRIPT
function printItems(items: readonly string[]) {
  items.forEach(item => console.log(item));
  // items.push("new");  // ❌ Compilation Error——The function is guaranteed not to be modified
}

let myItems = ["a", "b"];
printItems(myItems);  // Safety——myItems Will not be modified


3. نوع التوبول

التوبول هو مصفوفة ذات «طول ثابت وأنواع محددة لكل عنصر» — ويمكن اعتباره نسخة مبسطة من «البنية الثابتة المسماة».

(1) قواعد النحو الأساسية

TYPESCRIPT
// Defining Tuples:[Type1, Type2, ...]
let user: [string, number] = ["Charlie", 20];

// Access by Index
console.log(user[0]);  // "Charlie"(string Type)
console.log(user[1]);  // 20(number Type)

// Assignments must match in type and length
// user = [20, "Charlie"];  // ❌ Type order does not match
// user = ["Charlie"];      // ❌ Not long enough
// user = ["Charlie", 20, true];  // ❌ Exceeds the length limit

(2) الفرق بين المجموعات والمصفوفات

خاصية مصفوفة number[] توبول [string, number]
الطول أي ثابت
نوع العنصر جميعها متشابهة قد تختلف حسب الموقع
الوصول جميع العناصر من نفس النوع كل فهرس له نوع محدد
حالات الاستخدام مجموعات البيانات المماثلة مجموعات البيانات الصغيرة ذات البنية الثابتة

(3) تفكيك المجموعات

TYPESCRIPT
let pair: [string, number] = ["Apple", 5];

let [fruit, count] = pair;
console.log(fruit);   // "Apple"
console.log(count);   // 5

// Including remaining elements
let record: [string, number, ...boolean[]] = ["Test", 100, true, false, true];
let [name, score, ...flags] = record;
console.log(name);    // "Test"
console.log(score);   // 100
console.log(flags);   // [true, false, true]

(4) العناصر الاختيارية

يمكن تمييز العناصر الاختيارية في التوبول بعلامة ?:

TYPESCRIPT
let result: [string, number?] = ["Success"];

console.log(result[0]);  // "Success"
console.log(result[1]);  // undefined(Optional elements may be omitted.)
⚠️ ملاحظة: لا يمكن أن تظهر العناصر الاختيارية إلا في النهاية. [string?, number] غير صحيح — لا يمكن أن يتبع عنصر اختياري أي عناصر إلزامية.

(5) المجموعات المُعلمة

أدخلت TypeScript 4.0 تسميات التوبول، التي تجعل دلالة كل موضع أكثر وضوحًا:

TYPESCRIPT
let user: [name: string, age: number] = ["Charlie", 20];
let point: [x: number, y: number, z?: number] = [1.0, 2.5];

// Tags are only for document purposes,Does not affect the type——But the code's readability has improved significantly
function getRange(): [min: number, max: number] {
  return [0, 100];
}

let [min, max] = getRange();
console.log(`Scope:${min} - ${max}`);  // Scope:0 - 100

▶ مثال: المجموعات كقيم إرجاع للدوال

TYPESCRIPT
// Tuples are ideal for representing the return values of functions."Multiple values"
function divide(a: number, b: number): [quotient: number, remainder: number] {
  return [Math.floor(a / b), a % b];
}

let [quotient, remainder] = divide(17, 5);
console.log(`Quotient:${quotient},Remainder:${remainder}`);  // Quotient:3,Remainder:2

// A tuple represents a key-value pair
function entries(obj: Record<string, number>): [string, number][] {
  return Object.entries(obj) as [string, number][];
}

let scores = { Chinese Language: 90, Mathematics: 95, English: 88 };
for (let [subject, score] of entries(scores)) {
  console.log(`${subject}:${score}pts`);
}
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
Quotient:3,Remainder:2
Chinese Language:90pts
Mathematics:95pts
English:88pts


4. العمليات ذات الترتيب الأعلى على المصفوفات

(1) المصفوفات ذات الأنواع المجمعة مقابل المصفوفات ذات الأنواع المجمعة

TYPESCRIPT
// Union Type Arrays:Each element in the array can be number or string
let mixed: (number | string)[] = [1, "two", 3, "four"];

// Union Types for Arrays:Either... or number[],Either... or string[]
let uniform: number[] | string[] = [1, 2, 3];   // ✅
uniform = ["a", "b", "c"];                        // ✅
// uniform = [1, "two"];                          // ❌ Do not mix
🔥 خطأ شائع: (number | string)[] وnumber[] | string[] لهما معنيان مختلفان تمامًا! فالأول يشير إلى «مصفوفة مختلطة»، بينما يشير الثاني إلى «مصفوفة رقمية بحتة أو مصفوفة سلاسل بحتة».

(2) أمان أنواع أساليب المصفوفات

TYPESCRIPT
let nums: number[] = [3, 1, 4, 1, 5];

// sort An explicit comparison function is required,Otherwise, sort by string
nums.sort((a, b) => a - b);     // ✅ Number Sorting:[1, 1, 3, 4, 5]

// map Automatic Inference of Return Types
let doubled = nums.map(n => n * 2);   // Inferred as number[]
let asStrings = nums.map(String);      // Inferred as string[]

// filter Automatically Infer Element Types
let big = nums.filter(n => n > 2);    // Inferred as number[]

(3) تفريغ المصفوفات والأنواع

TYPESCRIPT
let a: number[] = [1, 2];
let b: number[] = [3, 4];
let merged: number[] = [...a, ...b];  // [1, 2, 3, 4]

// Tuple Unpacking
let prefix: [string, number] = ["No.", 0];
let full: [string, number, ...number[]] = [...prefix, 1, 2, 3];
// full = ["No.", 0, 1, 2, 3]


5. الخيارات المتاحة في عملية التطوير الفعلي

(1) متى تُستخدم المصفوفات

(2) متى تُستخدم المجموعات

(3) متى يُستخدم المصفوفة للقراءة فقط

▶ مثال: تمرين شامل — إدارة درجات الطلاب

TYPESCRIPT
// Represented as a tuple [Subject, Fractions]
type Score = [subject: string, score: number];

// Storing Multiple Grades in an Array
let scores: Score[] = [
  ["Chinese Language", 92],
  ["Mathematics", 88],
  ["English", 95],
  ["Physics", 78],
  ["Chemistry", 85]
];

// Calculate the average score
function average(scores: readonly Score[]): number {
  let total = scores.reduce((sum, [, score]) => sum + score, 0);
  return total / scores.length;
}

// Find the subject with the highest score
function topSubject(scores: readonly Score[]): Score {
  return scores.reduce((best, current) =>
    current[1] > best[1] ? current : best
  );
}

console.log("Average Score:" + average(scores).toFixed(1));
let [subject, score] = topSubject(scores);
console.log(`Subject with the Highest Score:${subject}(${score}pts)`);
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
Average Score:87.6
Subject with the Highest Score:English(95pts)


❓ أسئلة شائعة

س ما الفرق بين المجموعات (tuples) والكائنات العادية؟ ومتى ينبغي استخدام كل منها؟
ج يتم الوصول إلى المجموعات عن طريق الفهرس (tuple[0])، بينما يتم الوصول إلى الكائنات عن طريق المفتاح (obj.name). تعد التوبلات مناسبة للهياكل البسيطة والثابتة التي تحتوي على 2–3 عناصر (مثل الإحداثيات أو أزواج المفتاح-القيمة)؛ استخدم الكائنات أو الواجهات عندما يكون هناك أكثر من 3 عناصر أو عندما تكون الدلالات معقدة، لأن user.name أسهل في القراءة بكثير من user[0].
س ما الفرق بالضبط بين (number | سلسلة)[] و number[] | سلسلة[]؟
ج (number | string)[] هو مصفوفة حيث «يمكن أن يكون كل عنصر إما رقمًا أو سلسلة» — مما يسمح بالخلط بينهما، مثل [1, "a", 2]. number[] | string[] هو مصفوفة حيث «تكون المصفوفة بأكملها إما أرقامًا فقط أو سلاسل نصية فقط» — ولا يُسمح بالأنواع المختلطة، لذا فإن [1, "a"] غير صالح. والأخير هو اتحاد لنوعين من المصفوفات، وليس مصفوفة من نوع الاتحاد.
س لماذا لا تخضع عمليات «دفع» و«pop» في التوبلات لفحص النوع؟
ج هذا عيب تصميمي معروف في TypeScript. سيؤدي الوصول إلى عنصر خارج النطاق في المجموعات (مثل tuple[100]) إلى ظهور خطأ، ولكن يمكن تنفيذ الطرق push/pop في الوضع الصارم دون فحص النوع. يوصى باستخدام المجموعات readonly (readonly [string, number]) لمنع التعديل تمامًا.

📖 ملخص

📝 تمارين

  1. المشكلة الأساسية (مستوى الصعوبة ⭐): أنشئ مصفوفة string[] لتخزين أسماء خمس لغات برمجة، ثم استخدم forEach للتكرار عبرها وطباعتها. بعد ذلك، اكتب نسخة قابلة للقراءة فقط readonly string[]، وحاول تعديلها، ولاحظ رسالة الخطأ.
  2. مشكلة متقدمة (درجة الصعوبة ⭐⭐): عرّف دالة swap(tuple: [string, number]): [number, string] باستخدام مجموعة (tuple) لتبديل مواقع وأنواع العنصرين الموجودين في المجموعة. على سبيل المثال، تُرجع الدالة swap(["hello", 42]) القيمة [42, "hello"].
  3. مشكلة التحدي (الصعوبة ⭐⭐⭐): قم بتنفيذ دالة parseCSV(lines: string[]): [header: string[], ...rows: string[][]] تعمل على تحليل ملف نصي بتنسيق CSV إلى مجموعات — حيث يمثل السطر الأول العناوين، بينما تمثل الأسطر المتبقية البيانات. يجب أن يكون نوع القيمة المرجعة عبارة عن مجموعة مُعلمة تحتوي على العناصر المتبقية.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%