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) متى تُستخدم المجموعات
- مجموعات البيانات الصغيرة ذات الأطوال الثابتة والهياكل الثابتة (الإحداثيات
[x, y]، أزواج المفتاح-القيمة[key, value]) - الدوال التي تُرجع قيمًا متعددة
- هياكل بسيطة تتألف من عنصرين أو ثلاثة عناصر فقط (استخدم الكائنات أو الواجهات للهياكل الأكثر تعقيدًا)
(3) متى يُستخدم المصفوفة للقراءة فقط
- معلمات الدالة — تعهد بعدم تعديل المصفوفة التي تم تمريرها
- التكوين الثابت — منع التغييرات غير المقصودة
- قيمة الإرجاع لواجهة برمجة التطبيقات (API) — تُعلم المستخدم بأن البيانات غير قابلة للتعديل
▶ مثال: تمرين شامل — إدارة درجات الطلاب
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]) لمنع التعديل تمامًا.📖 ملخص
- هناك طريقتان لكتابة أنواع المصفوفات:
type[](موصى بها) وArray<type>؛ ولهما نفس التأثير تمامًا. - تُنشئ
readonly type[]وReadonlyArray<type>مصفوفات للقراءة فقط؛ ولا يمكنك إضافة عناصر إليها أو حذفها أو تعديلها. - التوبول
[type1, type2, ...]هو نوع خاص من المصفوفات ذات الطول الثابت، حيث يكون كل عنصر منه من نوع محدد. - تدعم المجموعات عملية تفكيك العناصر، والعناصر الاختيارية (
type?)، وعناصر الباقي (...type[])، والتسميات ([name: string]) (A | B)[](مصفوفة من أنواع الاتحاد) وA[] | B[](مصفوفة من أنواع الاتحاد) لهما معنيان مختلفان تمامًا
📝 تمارين
- المشكلة الأساسية (مستوى الصعوبة ⭐): أنشئ مصفوفة
string[]لتخزين أسماء خمس لغات برمجة، ثم استخدمforEachللتكرار عبرها وطباعتها. بعد ذلك، اكتب نسخة قابلة للقراءة فقطreadonly string[]، وحاول تعديلها، ولاحظ رسالة الخطأ. - مشكلة متقدمة (درجة الصعوبة ⭐⭐): عرّف دالة
swap(tuple: [string, number]): [number, string]باستخدام مجموعة (tuple) لتبديل مواقع وأنواع العنصرين الموجودين في المجموعة. على سبيل المثال، تُرجع الدالةswap(["hello", 42])القيمة[42, "hello"]. - مشكلة التحدي (الصعوبة ⭐⭐⭐): قم بتنفيذ دالة
parseCSV(lines: string[]): [header: string[], ...rows: string[][]]تعمل على تحليل ملف نصي بتنسيق CSV إلى مجموعات — حيث يمثل السطر الأول العناوين، بينما تمثل الأسطر المتبقية البيانات. يجب أن يكون نوع القيمة المرجعة عبارة عن مجموعة مُعلمة تحتوي على العناصر المتبقية.