TypeScript: أنواع الدوال في TypeScript
آخر تحديث: 2026-08-26
تُعد الدوال عنصراً أساسياً في لغة جافا سكريبت، وتضيف لغة تايب سكريبت نظام أنواع شامل لمعلمات الدوال وقيمها المرجعة — مما يضمن تحديد «مدخلات» الدالة و«مخرجاتها» بوضوح.
1. تعليقات توضيحية لنوع الدالة
(1) أنواع المعلمات والقيم المرجعة
function add(a: number, b: number): number {
return a + b;
}
let result = add(1, 2); // result Inferred as number
// add("1", "2"); // ❌ Parameter types do not match
// add(1); // ❌ Insufficient number of parameters
(2) استنتاج نوع القيمة المرجعة
يمكن لـ TypeScript استنتاج نوع القيمة المرجعة استنادًا إلى عبارة «return»، ولكن يُنصح بتحديده صراحةً:
// Return Type Inference——Can be inferred, but not recommended(It's easy to make mistakes when deriving large functions)
function multiply(a: number, b: number) {
return a * b; // Inference Return number
}
// Explicit Annotation——Recommendations(Purpose of the Document + Compile-time errors)
function divide(a: number, b: number): number {
if (b === 0) throw new Error("The divisor cannot be zero.");
return a / b;
}
(3) void نوع القيمة المرجعة
استخدم void عندما لا تحتوي الدالة على قيمة إرجاع:
function log(message: string): void {
console.log(message);
// None return Statement,Or return; —— All of them void
}
(4) لا تُرجع قيمةً أبدًا
استخدم never عندما لا تُرجع الدالة أي قيمة على الإطلاق — فهي إما ستُطلق استثناءً أو ستدخل في حلقة لا نهائية:
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) { }
}
| نوع القيمة المرجعة | المعنى |
|---|---|
void |
تم تنفيذ الدالة بشكل طبيعي، لكنها لم تُرجع أي قيمة |
never |
لا تنتهي الدالة أبدًا (تُحدث استثناءً أو تدخل في حلقة لا نهائية) |
▶ مثال: دوال المساعدة المُحدَّدة النوع
function clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max);
}
function formatCurrency(amount: number, symbol: string = "¥"): string {
return symbol + amount.toFixed(2);
}
console.log(clamp(150, 0, 100)); // 100
console.log(clamp(-5, 0, 100)); // 0
console.log(clamp(50, 0, 100)); // 50
console.log(formatCurrency(99.5)); // ¥99.50
console.log(formatCurrency(42, "$")); // $42.00
الناتج:
100
0
50
¥99.50
$42.00
2. المعلمات الاختيارية والمعلمات الافتراضية
(1) المعلمة الاختيارية ?
function greet(name: string, title?: string): string {
if (title) {
return `${title} ${name}`;
}
return `Hello,${name}`;
}
console.log(greet("Charlie")); // "Hello,Charlie"
console.log(greet("Charlie", "Engineer")); // "Engineer Charlie"
function greet(title?: string, name: string) إلى ظهور خطأ.
(2) المعلمات الافتراضية
function createUser(name: string, role: string = "viewer", active: boolean = true): string {
return `${name},Characters:${role},${active ? "Active" : "Not activated"}`;
}
console.log(createUser("Charlie")); // Charlie,Characters:viewer,Active
console.log(createUser("Diana", "editor")); // Diana,Characters:editor,Active
console.log(createUser("Eric", "admin", false)); // Eric,Characters:admin,Not activated
(3) المعلمات الاختيارية مقابل المعلمات الافتراضية
| الميزة | المعلمة الاختيارية title?: string |
المعلمة الافتراضية role: string = "viewer" |
|---|---|---|
| عند الاستدعاء | اختياري؛ القيمة غير محددة | اختياري؛ القيمة هي القيمة الافتراضية |
| النوع | string | undefined |
string (ليس الاتحاد غير المُعرَّف) |
| توصية | قد تكون القيمة غير محددة بالفعل | في معظم الحالات — من الأفضل تحديد قيمة افتراضية معقولة |
3. المعلمات المتبقية
استخدم صيغة ... لتجميع المعلمات المتبقية في مصفوفة:
function sum(first: number, ...rest: number[]): number {
return rest.reduce((total, n) => total + n, first);
}
console.log(sum(1)); // 1
console.log(sum(1, 2)); // 3
console.log(sum(1, 2, 3, 4)); // 10
(1) يجب أن تكون المعلمات المتبقية من نوع المصفوفة
function logAll(prefix: string, ...messages: string[]): void {
messages.forEach(msg => console.log(`${prefix}: ${msg}`));
}
logAll("DEBUG", "Start the service", "Connect to the Database", "Ready");
الناتج:
DEBUG: Start the service
DEBUG: Connect to the Database
DEBUG: Ready
4. التعبيرات من نوع الدالة
يمكن أيضًا تمرير الدوال بالقيمة — وفي هذه الحالة، يُستخدم تعبير نوع الدالة لتحديد النوع:
(1) تُعرِّف الأسماء المستعارة للأنواع أنواع الدوال
type MathOperation = (a: number, b: number) => number;
let add: MathOperation = (a, b) => a + b;
let subtract: MathOperation = (a, b) => a - b;
let multiply: MathOperation = (a, b) => a * b;
console.log(add(10, 5)); // 15
console.log(subtract(10, 5)); // 5
console.log(multiply(10, 5)); // 50
(2) أنواع دوال الاستدعاء
الاستخدام الأكثر شيوعًا لأنواع الدوال — وهو وصف توقيع دالة الاستدعاء:
function fetchData(url: string, onSuccess: (data: string) => void, onError: (error: Error) => void): void {
// Simulating Asynchronous Operations
if (url.startsWith("https://")) {
onSuccess("Data loaded successfully");
} else {
onError(new Error("Supports only HTTPS"));
}
}
fetchData(
"https://api.example.com",
data => console.log(data), // ✅ (data: string) => void
error => console.log(error.message) // ✅ (error: Error) => void
);
(3) تعريف أنواع الدوال باستخدام الواجهات
interface Comparator {
(a: number, b: number): number;
}
let ascending: Comparator = (a, b) => a - b;
let descending: Comparator = (a, b) => b - a;
let nums = [3, 1, 4, 1, 5];
console.log([...nums].sort(ascending)); // [1, 1, 3, 4, 5]
console.log([...nums].sort(descending)); // [5, 4, 3, 1, 1]
5. تحميل الدالة
يتيح تحميل الدالة اسم دالة واحدًا لدعم تركيبات مختلفة من أنواع المعلمات — ويتبع تحميل الدالة في TypeScript نمط «الإعلان + التنفيذ»:
(1) قواعد النحو الأساسية
// Overloaded Signatures——Describe the return type for each parameter combination
function format(value: number): string;
function format(value: string): string;
function format(value: Date): string;
// Implementing Signatures——Must be compatible with all overloaded signatures
function format(value: number | string | Date): string {
if (typeof value === "number") {
return value.toFixed(2);
} else if (typeof value === "string") {
return value.trim();
} else {
return value.toISOString();
}
}
console.log(format(3.14)); // "3.14"
console.log(format(" hello ")); // "hello"
console.log(format(new Date())); // "2024-..."
(2) ترتيب التحميل الزائد
تقوم TypeScript بمطابقة الطرق المُثقلة بالتحميل وفقًا لترتيب إعلانها، من الأعلى إلى الأسفل — لذا ينبغي وضع الطرق المُثقلة بالتحميل الأكثر تحديدًا أولاً:
// ✅ Correct Order——The specifics come first
function process(value: string): string;
function process(value: any): unknown;
// ❌ Incorrect Order——any Matches all parameters,The overloaded version that comes later will never be called.
// function process(value: any): unknown;
// function process(value: string): string;
▶ مثال: التحميل الزائد لتنفيذ معالجة الأحداث الآمنة من حيث النوع
function on(event: "click", handler: (x: number, y: number) => void): void;
function on(event: "keydown", handler: (key: string) => void): void;
function on(event: string, handler: Function): void {
console.log(`Registration Event:${event}`);
// Implementation details omitted...
}
// Automatically determines the correct parameter types upon invocation
on("click", (x, y) => {
console.log(`Click here:(${x}, ${y})`); // x, y Inferred as number
});
on("keydown", (key) => {
console.log(`Press the button:${key}`); // key Inferred as string
});
الناتج:
// Executed successfully
6. أنواع دوال السهم
(1) تعليقات الأنواع لدوال السهم
const add = (a: number, b: number): number => a + b;
// When acting as a callback,Parameter types can usually be inferred
const nums = [1, 2, 3];
const doubled = nums.map(n => n * 2); // n Inferred as number
const asStrings = nums.map(n => String(n)); // n Inferred as number
(2) الدوال السهمية وthis
دوال السهم لا تربط this الخاصة بها — بل ترث this الخارجية:
class Timer {
seconds = 0;
start() {
// Arrow Functions——this Orientation Timer Examples
setInterval(() => {
this.seconds++;
console.log(`${this.seconds}s`);
}, 1000);
}
startBroken() {
// Ordinary Functions——this Points to the global or undefined(Strict Mode)
setInterval(function () {
// this.seconds++; // ❌ Runtime this No Timer
}, 1000);
}
}
▶ مثال: المعلمات المتبقية والتحميل الزائد للدوال
// Rest parameters — collecting variable arguments
function log(context: string, ...messages: string[]): void {
console.log(`[${context}] ${messages.join(", ")}`);
}
log("App", "started", "initialized", "ready");
// [App] started, initialized, ready
// Function overloads — different return types per signature
function parse(input: string): Date;
function parse(input: number): Date;
function parse(input: string | number): Date {
return typeof input === "string"
? new Date(input)
: new Date(input);
}
let fromStr = parse("2024-01-01");
let fromNum = parse(1704067200000);
console.log(fromStr.toISOString()); // "2024-01-01T00:00:00.000Z"
الناتج:
[App] started, initialized, ready
2024-01-01T00:00:00.000Z
❓ أسئلة شائعة
return)، ولكن يُنصح بتحديده للدوال التي يزيد طولها عن ثلاثة أسطر.void وundefined؟void تعني أن «الدالة لا تهتم بقيمة الإرجاع» — فقد تحتوي الدالة على عبارة return أو لا تحتوي عليها، ويجب على المستدعي ألا يستخدم قيمة الإرجاع. undefined هو نوع محدد — حيث تُرجع الدالة صراحةً undefined. في التطوير الفعلي، تستخدم جميع الدوال التي لا تحتوي على قيمة إرجاع void.function fn(x: string | number) إلا أن يصف أن «المعلمة يمكن أن تكون أحد هذه الأنواع»، لكن جميع تركيبات المعلمات تُرجع النوع نفسه. أما التحميل الزائد فيسمح بـ«أن تعيد تركيبات المعلمات المختلفة أنواعًا مختلفة» — وهو ما لا تستطيع أنواع الاتحاد القيام به. إذا كانت أنواع المعلمات مرنة لكن نوع الإرجاع موحدًا، فإن استخدام نوع الاتحاد يكون أكثر إيجازًا؛ استخدم التحميل الزائد عندما تكون أنواع الإرجاع المختلفة مطلوبة.function fn(x?: string = "hi") يمثل خطأً في بناء الجملة — فالمعلمات الافتراضية تُعتبر «اختيارية» ضمناً، لذا لا داعي لإضافة ?. x: string = "hi" يعادل x?: string، لكن قيمته هي «hi» وليست غير محددة.📖 ملخص
- تعليقات أنواع الدوال: يجب إضافة تعليقات لأنواع المعلمات؛ ويُوصى بإضافة تعليقات لأنواع القيم المرجعة؛ ويشير "void" إلى عدم وجود قيمة مرجعة، بينما يشير "never" إلى أن الدالة لا ترجع أبدًا.
- استخدم
?للمعلمات الاختيارية (قد تكون القيمة غير محددة)؛ واستخدم= defaultValueللمعلمات الافتراضية (من الأفضل وجود قيمة افتراضية) - المعلمات المتبقية
...args: type[]تجمع المعلمات الزائدة في مصفوفة - تُستخدم التعبيرات من نوع الدالة
type Fn = (parameter) => returnValueلوصف دوال الاستدعاء والدوال ذات الترتيب الأعلى - يتبع تحميل الدالة نمط «الإعلان + التنفيذ» — حيث يحدد الإعلان نوع القيمة المرجعة لكل مجموعة من المعلمات، ويجب أن يكون التنفيذ متوافقًا مع جميع حالات التحميل.
📝 تمارين
- تمرين أساسي (مستوى الصعوبة ⭐): اكتب ثلاث دوال —
add(a, b)للجمع، وsubtract(a, b)للطرح، وmultiply(a, b)للضرب — بحيث تكون كل من المعلمات والقيم المرجعة من النوعnumber. استخدم تعبيرات نوع الدالة لإعلان الأنواع بشكل موحد. - مشكلة متقدمة (درجة الصعوبة ⭐⭐): اكتب دالة
buildQuery(params: Record<string, string | number | boolean>)تقوم بتحويل كائن إلى سلسلة استعلام URL. على سبيل المثال،{ page: 1, size: 10, active: true }→"page=1&size=10&active=true". - التحدي (الصعوبة ⭐⭐⭐): قم بتنفيذ ذلك باستخدام تحميل الدوال
createElement(tag, props): عندما تكون العلامة "input"، يجب أن تكون الخصائصtype: string؛ وعندما تكون العلامة "a"، يجب أن تكون الخصائصhref: string؛ وعندما تكون العلامة "div"، تكون الخصائص كائنًا عامًا. أرجع كائن وصف من نوع مختلف لكل حالة.