Typealias — ما هو، التركيب والاستخدام في Kotlin

المؤلف: IT Sectr نُشر: 2026-06-23 وقت القراءة: 7 دق

Typealias هي آلية في Kotlin لإنشاء اسم بديل لنوع موجود. تسمح الكلمة المفتاحية typealias باستبدال تعريف النوع المعقد باسم مستعار قصير وواضح دون إنشاء نوع جديد. وفقاً لتوثيق Kotlin (2026)، يحسّن typealias قابلية قراءة الكود، خاصة في تواقيع الدوال ذات الأنواع الوظيفية. Typealias يجعل الكود موثقاً ذاتياً عن طريق استبدال التعريفات المطولة بأنواع مسماة واضحة.

الملامح الرئيسية

  • Typealias — اسم مستعار لنوع موجود لا ينشئ نوعاً جديداً
  • الأنواع الوظيفية — typealias يستبدل (T) -> R المعقدة بأسماء قابلة للقراءة مثل Callback
  • الأدوية (Generics) — typealias يدعم المعاملات العامة: typealias ListMapper = (T) -> T
  • الفئات المتداخلة — typealias يختصر الوصول إلى الفئات المتداخلة من الحزم الأخرى
  • أمان الأنواع — typealias لا يضيف فحوصات في وقت الترجمة؛ الاسم المستعار قابل للتبادل بالكامل مع الأصل

ما هو typealias؟

Typealias (الاسم المستعار للنوع) هو تعريف يقدم اسماً بديلاً لنوع موجود. الصيغة: typealias الاسمالجديد = النوعالموجود. بعد التعريف، يمكن استخدام الاسمالجديد حيثما يُتوقع النوعالموجود — يعاملهما المترجم كنفس النوع. على مستوى البايت كود، لا يترك typealias أي أثر: جميع معلومات الاسم المستعار تُمحى في وقت الترجمة.

الهدف الرئيسي من typealias هو تحسين قابلية قراءة الكود. بدلاً من توقيع مطول fun process(callback: (Result) -> Unit)، يمكن كتابة typealias Callback = (Result) -> Unit واستخدام Callback كنوع المعامل. هذا مفيد بشكل خاص عندما يتكرر نفس النوع الوظيفي في عدة أماكن في الكود: يعمل الاسم المستعار كنقطة تعريف واحدة ويوثق الغرض من النوع.

Typealias لا ينشئ نوعاً جديداً — إنه مجرد مرادف. المتغيرات من نوع Callback و (Result) -> Unit قابلة للتبادل بالكامل. لن ينتج المترجم خطأ إذا تم تمرير دالة مباشرة إلى دالة تتوقع Callback. هذا يفرّق typealias عن inline class (value class)، الذي ينشئ نوعاً مغلفاً جديداً مع فحص في وقت الترجمة. Typealias هو إعادة تسمية، وليس تغليفاً.

Typealias للأنواع الوظيفية

حالة الاستخدام الأكثر شيوعاً لـ typealias في Kotlin هي الأنواع الوظيفية. التواقيع الطويلة مثل (Int, String) -> Boolean أو (List) -> Result تجعل الكود صعب القراءة. Typealias يحوّلها إلى أسماء قصيرة وذات معنى توثّق الغرض من الدالة: typealias Validator = (String) -> Boolean يحدد أن هذا مدقق سلاسل.

kotlin
// Without typealias
fun findUsers(
    filter: (List<User>) -> List<User>
): List<User>

// With typealias
typealias UserFilter = (List<User>) -> List<User>

fun findUsers(filter: UserFilter): List<User>

// Usage in class
typealias OnClickListener = (View) -> Unit

class Button {
    var onClick: OnClickListener = {}
}

في المثال، الاسم المستعار UserFilter يخفي النوع الوظيفي المعقد (List) -> List خلف اسم قصير. يصبح توقيع findUsers مقروءاً: "يقبل UserFilter، ويعيد List". الاسم المستعار OnClickListener يجعل الكود يشبه تعريف واجهة ولكن دون عبء إنشاء واجهة أو فئة مجردة منفصلة. وفي الوقت نفسه، تستمر الدوال الممررة والدوال المجهولة في العمل كالمعتاد — typealias لا يتطلب تغييرات في الكود المستدعي.

Typealias مع الأدوية (Generics)

Typealias يدعم المعاملات العامة (الأدوية)، مما يجعله أكثر مرونة. يمكن تعريف typealias Mapper = (T) -> R واستخدامه مع أي أنواع. يقوم المترجم باستبدال أنواع محددة مكان المعاملات مع كل استخدام للاسم المستعار، مع الحفاظ على سلامة الأنواع الكاملة.

kotlin
// Generic typealias
typealias Mapper<T, R> = (T) -> R
typealias Provider<T> = () -> T
typealias ListTransformer<T> = (List<T>) -> List<T>

fun processNumbers(mapper: Mapper<Int, String>) {
    // mapper type is (Int) -> String
}

fun main() {
    val config: Provider<String> = { "default config" }
    val reverse: ListTransformer<Int> = { it.reversed() }
}

في القائمة، Mapper هو اسم مستعار عام لأي تحويل من T إلى R. Provider هو مزود قيمة (مصنع بدون وسائط). ListTransformer هي دالة تحويل قائمة. عند استدعاء processNumbers(mapper: Mapper)، يوسّع المترجم الاسم المستعار إلى (Int) -> String. الأدوية تجعل typealias أداة عالمية مناسبة لأي سياق دون تكرار التعريفات.

Typealias للأسماء المتداخلة والطويلة

الفئات المتداخلة والأنواع المعلمة الطويلة هي مجال آخر حيث يبسّط typealias الكود بشكل كبير. إذا كانت فئة عميقة في تسلسل هرمي للتداخل (Outer.Inner.Nested)، فإن الإشارة إليها بالاسم الكامل تثقل الكود. Typealias يختصر هذا الوصول ويجعله أكثر قابلية للقراءة. هذا مهم بشكل خاص للفئات من المكتبات الخارجية ذات الأسماء الطويلة.

kotlin
// Alias for nested class
class NetworkResponse {
    class Error(val code: Int, val message: String)
}
typealias NetworkError = NetworkResponse.Error

// Alias for long library type
typealias UserId = Long
typealias JsonMap = Map<String, Any?>

fun process(error: NetworkError) {
    println("${error.code}: ${error.message}")
}

fun parseJson(data: JsonMap): UserId {
    return data["id"] as? Long ?: 0L
}

في المثال، NetworkError هو اسم مستعار للفئة المتداخلة NetworkResponse.Error. باستيراد typealias، يمكن استخدام NetworkError كنوع عادي دون الكشف عن التسلسل الهرمي للتداخل. JsonMap يوثق أن الخريطة تمثل كائن JSON. UserId يوضح الغرض من Long في سياق معين — يفهم القارئ فوراً أن هذا معرف مستخدم، وليس رقماً عشوائياً. ومع ذلك، typealias لا يمنع تمرير Long عادي حيث يُتوقع UserId — لذلك يلزم value class.

Typealias مقابل inline class: الفروق

Typealias و inline class (value class) يحلان مشاكل مختلفة، على الرغم من أن كلاهما يقدم اسماً جديداً لنوع. Typealias هو مجرد مرادف: متغير من نوع UserId = Long يقبل أي Long دون فحص. Inline class يغلف قيمة في نوع جديد يتم فحصه في وقت الترجمة: لا يمكن تمرير Long عادي حيث يُتوقع inline class UserId دون تحويل صريح.

الخاصيةTypealiasInline class
نوع جديدلا — مرادف للأصلنعم — نوع جديد مع فحوصات
الأداءصفر — يُمحى بالكاملصفر — يُزال الغلاف في البايت كود
الوراثةلالا (فئة نهائية)
طرق خاصةلانعم — يمكن تعريف دوال
أمان الأنواعلا — قابل للتبادل مع الأصلنعم — المترجم يميّز الأنواع

يوضح الجدول الفرق بين الآليتين. Typealias مناسب للأسماء المختصرة وتوثيق الكود عندما لا تكون الكتابة الصارمة مطلوبة. Inline class عبر الكلمة المفتاحية value class (سابقاً inline class) ضرورية عندما يكون من المهم التمييز بين قيم مختلفة دلالياً من نفس النوع البدائي. على سبيل المثال، UserId و OrderId كلاهما Long، ولكن تمرير أحدهما حيث يُتوقع الآخر هو خطأ منطقي تمنعه value class في وقت الترجمة.

الأسئلة الشائعة

كيف يختلف typealias عن import alias؟

Import alias (import com.example.LongName as Short) يعمل على مستوى الاستيراد — يختصر الاسم فقط في الملف الحالي. Typealias يعلن اسماً مستعاراً عاماً متاحاً في جميع أنحاء المشروع بعد الاستيراد.

هل يمكن استخدام typealias لإنشاء نوع متكرر؟

نعم، typealias يدعم التعريفات المتكررة للأنواع الوظيفية، ولكن بحذر: typealias Rec = (T) -> Rec يعمل، ولكن المراجع المتكررة إلى object لا. يقوم المترجم بفحص الدورات وينتج خطأ للتعريفات اللانهائية.

هل يؤثر typealias على الأداء؟

لا، typealias يُمحى بالكامل في وقت الترجمة. يُستخدم النوع الأصلي على مستوى البايت كود ووقت التشغيل دون أي غلاف. الأداء مطابق لاستخدام النوع الأصلي مباشرة.

ما هو أقصى مستوى تداخل لـ typealias؟

Typealias يمكن أن يشير إلى typealias آخر — وهذا يسمى سلسلة أسماء مستعارة. عمق السلسلة غير محدود رسمياً، ولكن من أجل القراءة يُوصى بما لا يزيد عن 2–3 مستويات. يقوم المترجم بحل السلسلة بالكامل في مرحلة التحليل.

هل يمكن تعريف typealias داخل دالة؟

لا، typealias هو تعريف على المستوى الأعلى أو عضو في فئة/كائن. لا يمكن تعريف typealias داخل الدوال. للاختصار المحلي للأنواع، استخدم import alias داخل الملف أو ضع typealias على مستوى الوحدة.

الخلاصة

  • Typealias — مرادف لنوع موجود لا ينشئ نوعاً جديداً ويُمحى في وقت الترجمة
  • الأنواع الوظيفية — حالة الاستخدام الرئيسية: typealias يستبدل (T) -> R باسم قابل للقراءة مثل Callback
  • الأدوية (Generics) في typealias تسمح بإنشاء أسماء مستعارة عامة Mapper لأي نوع
  • الفئات المتداخلة — typealias يختصر الوصول إلى الأنواع المتداخلة بعمق والأسماء الطويلة من المكتبات
  • أمان الأنواع غائب: typealias قابل للتبادل بالكامل مع النوع الأصلي
  • Value class — بديل لـ typealias عندما يكون الفحص الصارم للأنواع بتكلفة صفرية في وقت التشغيل مطلوباً
  • قابلية القراءة — الميزة الرئيسية: أسماء الأنواع ذات المعنى تجعل الكود موثقاً ذاتياً دون عبء إضافي

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا