TypeScript: أنواع الدوال في TypeScript

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

تُعد الدوال عنصراً أساسياً في لغة جافا سكريبت، وتضيف لغة تايب سكريبت نظام أنواع شامل لمعلمات الدوال وقيمها المرجعة — مما يضمن تحديد «مدخلات» الدالة و«مخرجاتها» بوضوح.

1. تعليقات توضيحية لنوع الدالة

(1) أنواع المعلمات والقيم المرجعة

TYPESCRIPT
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»، ولكن يُنصح بتحديده صراحةً:

TYPESCRIPT
// 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 عندما لا تحتوي الدالة على قيمة إرجاع:

TYPESCRIPT
function log(message: string): void {
  console.log(message);
  // None return Statement,Or return; —— All of them void
}

(4) لا تُرجع قيمةً أبدًا

استخدم never عندما لا تُرجع الدالة أي قيمة على الإطلاق — فهي إما ستُطلق استثناءً أو ستدخل في حلقة لا نهائية:

TYPESCRIPT
function throwError(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) { }
}
نوع القيمة المرجعة المعنى
void تم تنفيذ الدالة بشكل طبيعي، لكنها لم تُرجع أي قيمة
never لا تنتهي الدالة أبدًا (تُحدث استثناءً أو تدخل في حلقة لا نهائية)

▶ مثال: دوال المساعدة المُحدَّدة النوع

TYPESCRIPT
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
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
100
0
50
¥99.50
$42.00


2. المعلمات الاختيارية والمعلمات الافتراضية

(1) المعلمة الاختيارية ?

TYPESCRIPT
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) المعلمات الافتراضية

TYPESCRIPT
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. المعلمات المتبقية

استخدم صيغة ... لتجميع المعلمات المتبقية في مصفوفة:

TYPESCRIPT
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) يجب أن تكون المعلمات المتبقية من نوع المصفوفة

TYPESCRIPT
function logAll(prefix: string, ...messages: string[]): void {
  messages.forEach(msg => console.log(`${prefix}: ${msg}`));
}

logAll("DEBUG", "Start the service", "Connect to the Database", "Ready");

الناتج:

TEXT 📖 للعرض فقط
DEBUG: Start the service
DEBUG: Connect to the Database
DEBUG: Ready


4. التعبيرات من نوع الدالة

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

(1) تُعرِّف الأسماء المستعارة للأنواع أنواع الدوال

TYPESCRIPT
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) أنواع دوال الاستدعاء

الاستخدام الأكثر شيوعًا لأنواع الدوال — وهو وصف توقيع دالة الاستدعاء:

TYPESCRIPT
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) تعريف أنواع الدوال باستخدام الواجهات

TYPESCRIPT
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) قواعد النحو الأساسية

TYPESCRIPT
// 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 بمطابقة الطرق المُثقلة بالتحميل وفقًا لترتيب إعلانها، من الأعلى إلى الأسفل — لذا ينبغي وضع الطرق المُثقلة بالتحميل الأكثر تحديدًا أولاً:

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;

▶ مثال: التحميل الزائد لتنفيذ معالجة الأحداث الآمنة من حيث النوع

TYPESCRIPT
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
});
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
// Executed successfully


6. أنواع دوال السهم

(1) تعليقات الأنواع لدوال السهم

TYPESCRIPT
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 الخارجية:

TYPESCRIPT
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);
  }
}

▶ مثال: المعلمات المتبقية والتحميل الزائد للدوال

TYPESCRIPT
// 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"
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
[App] started, initialized, ready
2024-01-01T00:00:00.000Z


❓ أسئلة شائعة

س هل يجب تحديد أنواع العائد للدوال بشكل صريح؟
ج يُنصح بتحديدها. على الرغم من أن TypeScript يمكنها استنتاجها، إلا أن التحديد الصريح يوفر ثلاث مزايا: (1) التوثيق — يكون نوع العائد واضحًا على الفور؛ (2) منع إرجاع نوع خاطئ عن غير قصد؛ (3) تحديد موقع الخطأ بشكل أفضل — يتم الإبلاغ عن الأخطاء في توقيع الدالة بدلاً من نقطة الاستدعاء. يمكنك حذف نوع العائد للدوال الصغيرة (المكونة من سطر واحد return)، ولكن يُنصح بتحديده للدوال التي يزيد طولها عن ثلاثة أسطر.
س ما الفرق بين أنواع الإرجاع void وundefined؟
ج void تعني أن «الدالة لا تهتم بقيمة الإرجاع» — فقد تحتوي الدالة على عبارة return أو لا تحتوي عليها، ويجب على المستدعي ألا يستخدم قيمة الإرجاع. undefined هو نوع محدد — حيث تُرجع الدالة صراحةً undefined. في التطوير الفعلي، تستخدم جميع الدوال التي لا تحتوي على قيمة إرجاع void.
س ما الفرق بين تحميل الدالة (overloading) ومعلمات أنواع الاتحاد (union type)؟
ج لا يمكن لنوع الاتحاد function fn(x: string | number) إلا أن يصف أن «المعلمة يمكن أن تكون أحد هذه الأنواع»، لكن جميع تركيبات المعلمات تُرجع النوع نفسه. أما التحميل الزائد فيسمح بـ«أن تعيد تركيبات المعلمات المختلفة أنواعًا مختلفة» — وهو ما لا تستطيع أنواع الاتحاد القيام به. إذا كانت أنواع المعلمات مرنة لكن نوع الإرجاع موحدًا، فإن استخدام نوع الاتحاد يكون أكثر إيجازًا؛ استخدم التحميل الزائد عندما تكون أنواع الإرجاع المختلفة مطلوبة.
س هل يمكن استخدام المعلمات الافتراضية والمعلمات الاختيارية معًا؟
ج لا. function fn(x?: string = "hi") يمثل خطأً في بناء الجملة — فالمعلمات الافتراضية تُعتبر «اختيارية» ضمناً، لذا لا داعي لإضافة ?. x: string = "hi" يعادل x?: string، لكن قيمته هي «hi» وليست غير محددة.

📖 ملخص

📝 تمارين

  1. تمرين أساسي (مستوى الصعوبة ⭐): اكتب ثلاث دوال — add(a, b) للجمع، وsubtract(a, b) للطرح، وmultiply(a, b) للضرب — بحيث تكون كل من المعلمات والقيم المرجعة من النوع number. استخدم تعبيرات نوع الدالة لإعلان الأنواع بشكل موحد.
  2. مشكلة متقدمة (درجة الصعوبة ⭐⭐): اكتب دالة buildQuery(params: Record<string, string | number | boolean>) تقوم بتحويل كائن إلى سلسلة استعلام URL. على سبيل المثال، { page: 1, size: 10, active: true }"page=1&size=10&active=true".
  3. التحدي (الصعوبة ⭐⭐⭐): قم بتنفيذ ذلك باستخدام تحميل الدوال createElement(tag, props): عندما تكون العلامة "input"، يجب أن تكون الخصائص type: string؛ وعندما تكون العلامة "a"، يجب أن تكون الخصائص href: string؛ وعندما تكون العلامة "div"، تكون الخصائص كائنًا عامًا. أرجع كائن وصف من نوع مختلف لكل حالة.
Web-Tutorial.com

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

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

100%