0Pricing
TypeScript Academy · درس

الواجهات العامة والأسماء المستعارة العامة للأنواع

عرّف واجهات عامة وأسماء مستعارة عامة للأنواع، وأضف القيود والقيم الافتراضية، وافهم الحالات التي يتفوّق فيها كل منها.

الواجهات العامة والأسماء المستعارة العامة للأنواع درس مجاني في TypeScript Academy على CoddyKit. هذا هو الدرس 1 من أصل 3. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في TypeScript Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة TypeScript Academy 3 دروس في المجموع.

مقدمة

الهدف: إنشاء بنى قابلة لإعادة الاستخدام باستخدام الواجهات العامة والأسماء المستعارة للأنواع. ستضيف قيوداً وقِيماً افتراضية، وستتعلم الفروق الأساسية.

نظرة عامة على الدرس

الهدف: طبّق التزامن المنظّم باستخدام coroutineScope، وافهم انتشار الاستثناءات، واستخدم أدوات الإلغاء بأمان.

الأفكار الأساسية

  • ينتظر coroutineScope اكتمال جميع coroutines التابعة؛ ويؤدي الفشل إلى إلغاء coroutines الشقيقة.
  • يفشل launch فورًا داخل النطاق؛ ويُظهر async الأخطاء عند استدعاء await().
  • يلغي withTimeout العمل بعد تجاوز حد زمني.
  • غلّف النطاقات باستخدام try/catch لمعالجة الاستثناءات.

واجهة عامة

تحتوي الواجهة العامة على معامل نوع. ويستبدل المستدعون هذا المعامل بأنواع محددة، مثل Box<number>.

interface Box<T> {
  value: T;
}

const nBox: Box<number> = { value: 42 };
const sBox: Box<string> = { value: "ts" };
console.log(nBox.value, sBox.value);

اسم مستعار عام للنوع

يمكن أيضاً أن يكون الاسم المستعار للنوع عاماً، وأن يعبّر عن كائنات أو دوال أو اتحادات أو تقاطعات.

type Pair<A, B> = { first: A; second: B };

const p1: Pair<number, string> = { first: 1, second: "one" };
const p2: Pair<boolean, boolean> = { first: true, second: false };
console.log(p1, p2);

سلوك انتظار النطاق

ينشئ coroutineScope نطاقًا تابعًا لا يكتمل إلا بعد انتهاء coroutines التابعة له.

import kotlinx.coroutines.*

suspend fun doTwoTasks(): Unit = coroutineScope {
    // Both run concurrently and the scope waits for them
    launch { delay(150); println("Task A done") }
    launch { delay(100); println("Task B done") }
    // returning Unit implicitly after children complete
}

fun main() = runBlocking {
    doTwoTasks()
    println("Scope completed")
}

الفشل يلغي الأشقاء

إذا طرحت إحدى coroutines التابعة استثناءً، فإن النطاق يلغي coroutines الشقيقة ويعيد طرح الاستثناء إلى المستدعي؛ استخدم try/catch في موضع الاستدعاء.

import kotlinx.coroutines.*

suspend fun failingGroup() = coroutineScope {
    val a = launch {
        try {
            repeat(5) { i ->
                println("A $i"); delay(60)
            }
        } finally {
            println("A cancelled")
        }
    }
    launch {
        delay(120)
        throw IllegalStateException("boom") // failure in child
    }
    a.join() // will be cancelled when sibling fails
}

fun main() = runBlocking {
    try {
        failingGroup()
    } catch (e: Exception) {
        println("Caught in caller: ${e.message}")
    }
    println("Caller continues")
}

القيود

أضف قيداً باستخدام extends كي يعرض T الأعضاء المطلوبة لأساليب الواجهة، مثل id.

interface Repository<T extends { id: number }> {
  getById(id: number): T | undefined;
  save(entity: T): void;
}

type User = { id: number; name: string };

const memRepo: Repository<User> = {
  store: [] as User[],
  getById(id) {
    return this.store.find(u => u.id === id);
  },
  save(u) {
    this.store.push(u);
  }
} as unknown as Repository<User>;

memRepo.save({ id: 1, name: "Ada" });
console.log(memRepo.getById(1));

أخطاء async وawait

تُرفع استثناءات async عند استدعاء await()؛ عالجها باستخدام try/catch.

import kotlinx.coroutines.*

suspend fun parseAsync(s: String) = coroutineScope {
    val deferred = async {
        delay(50)
        s.toInt() // may throw NumberFormatException
    }
    try {
        println("Result = ${deferred.await()}") // error appears here
    } catch (e: NumberFormatException) {
        println("Handled parse error: ${e::class.simpleName}")
    }
}

fun main() = runBlocking {
    parseAsync("12")
    parseAsync("xx")
}

القيم الافتراضية والتوسعة

وفّر معاملات أنواع افتراضية لتسهيل الاستخدام، وابنِ على الأنواع باستخدام الأدوات، مثل Readonly<Box<T>>.

interface ApiResponse<T = unknown> {
  data: T;
  ok: boolean;
}

type ReadonlyBox<T> = Readonly<Box<T>>;

const r1: ApiResponse = { data: "ok", ok: true };      // T defaults to unknown
const r2: ApiResponse<number> = { data: 200, ok: true };
const rb: ReadonlyBox<string> = { value: "fixed" };
// rb.value = "change"; // Error: readonly

إلغاء withTimeout

استخدم withTimeout لتحديد مدة العمل؛ إذ يلغي العملية التابعة ويرمي TimeoutCancellationException.

import kotlinx.coroutines.*

suspend fun slowOp(): Int {
    delay(300) // pretend work
    return 42
}

fun main() = runBlocking {
    try {
        val result = withTimeout(150) { slowOp() } // cancels after 150ms
        println("Got $result")
    } catch (e: TimeoutCancellationException) {
        println("Timed out and cancelled")
    }
}

فروق الدمج

تدعم الواجهات دمج التصريحات. أما الأسماء المستعارة للأنواع فلا يمكن دمجها؛ وتؤدي الأسماء المكررة إلى أخطاء.

interface Settings { theme: string }
interface Settings { lang: string }
// Merged: Settings has { theme: string; lang: string }
const s: Settings = { theme: "dark", lang: "en" };

// type Settings = { foo: string };
// Error: Duplicate identifier 'Settings' for type aliases (no merging)

قاعدة فشل التزامن المنظّم

في coroutineScope، ماذا يحدث إذا فشلت إحدى coroutines التابعة باستثناء؟

فحص الواجهات مقابل الأنواع

فحص سريع: ما العبارة الصحيحة بشأن الواجهات العامة مقابل الأسماء المستعارة للأنواع؟

خلاصة

خلاصة: استخدم الواجهات العامة والأسماء المستعارة للأنواع لنمذجة البنى القابلة لإعادة الاستخدام. أضف القيود والقيم الافتراضية، وتذكّر أن الواجهات وحدها تُدمج.

خلاصة

خلاصة: استخدم coroutineScope لتجميع العمل؛ إذ تلغي العملية التابعة الفاشلة coroutines الشقيقة. عالج الأخطاء باستخدام try/catch، وأظهر إخفاقات async عند استدعاء await()، وألغِ المهام الطويلة باستخدام withTimeout.

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

هل درس «الواجهات العامة والأسماء المستعارة العامة للأنواع» مجاني؟

نعم — نص درس «الواجهات العامة والأسماء المستعارة العامة للأنواع» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة TypeScript Academy، انتقل إلى CoddyKit PRO. تتضمن دورة TypeScript Academy 3 دروس في المجموع.

ماذا ستتعلم في «الواجهات العامة والأسماء المستعارة العامة للأنواع»؟

عرّف واجهات عامة وأسماء مستعارة عامة للأنواع، وأضف القيود والقيم الافتراضية، وافهم الحالات التي يتفوّق فيها كل منها. تتمرن على TypeScript Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ TypeScript Academy؟

لا تُشترط خبرة سابقة. TypeScript Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 3.

كم من الوقت يستغرق درس «الواجهات العامة والأسماء المستعارة العامة للأنواع»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس TypeScript Academy هذا؟

نعم. كل درس في TypeScript Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. الواجهات العامة والأسماء المستعارة العامة للأنواع
  2. الأنواع الشرطية (مقدمة) والتوزيع على الاتحادات
  3. أنماط قابلة لإعادة الاستخدام لنماذج البيانات
← العودة إلى TypeScript Academy