انواع - چگونه: تایپاسکریپت تایپگذاری تو در تو A>


آیا امکان دارد چنین نوعی تایپینگ در تایپاسکریپت داشته باشیم؟

interface Worker<T> {
    renderChunk: (projectUrl: string, from: number, to: number) => Promise<T>;
}

interface WorkerPool<W<U>> {
    addWorker(worker: W, address: number): void;

    getIdleWorker(): W | null;
}

اما من همچنین میخواهم نوعی محدودیت داشته باشم که بررسی کند W باید یک پیادهسازی از Worker باشد، فرض کنید به عنوان مثال شما یک پیادهسازی از Worker به صورت زیر دارید:

class RenderWorker implements Worker<string[]> {
    renderChunk: (projectUrl: string, from: number, to: number) => Promise<string[]> {
         return Promise.resolve(['Foo'])
    }
}

پیادهسازی زیر باید توسط تایپاسکریپت قابل قبول باشد:

class RenderWorkerPool implements WorkerPool<RenderWorker> {} 

با این حال، این مورد نباید قابل قبول باشد زیرا string پیادهسازی Worker نیست

class RenderWorkerPool implements WorkerPool<string> {} 

پاسخ شماره ۱

بله، با استفاده از نوعهای عمومی محدودشده، میتوانید اطمینان حاصل کنید که W از Worker توسعه یافته است.

interface WorkerPool<W extends AaWorker<any>> {
    addWorker(worker: W, address: number): void;

    getIdleWorker(): W | null;
}

لینک زمین بازی

به دلیل جنریک تو در تو، اگر بخواهید درباره نوع کارگر استدلال کنید، باید آن را نیز مشخص کنید:

interface WorkerPool<U, W extends AaWorker<U>> {
    addWorker(worker: W, address: number): void;

    getIdleWorker(): W | null;
}

لینک زمین بازی

اما همانطور که برناردو دوآرته در نظرات اشاره میکند، ممکن است اصلاً نیازی به استفاده از جنریک برای Worker نداشته باشید. در عوض، میتوانید هر پیادهسازی سازگار با Worker را با نوع جنریک مناسب بگیرید:

interface WorkerPool<U> {
    addWorker(worker: AaWorker<U>, address: number): void;

    getIdleWorker(): AaWorker<U> | null;
}

لینک زمین بازی

(من Worker را به AaWorker در بالا تغییر دادهام، فقط بهخاطر اینکه هیچ تداخلی در نام بین Worker شما و اشیاء داخلی Web Worker ایجاد نشود.)

پاسخ شماره ۲

فکر میکنم شما این را میخواهید:

interface WorkerPool<W extends Worker<unknown>> {
  addWorker(worker: W, address: number): void;
  getIdleWorker(): W | null;
}

W توسط Worker<unknown> محدود شده است. بنابراین W به عنوان یک Worker استنتاج میشود و نوع ژنریک T آن کارگر نیز به عنوان بخشی از آن استنتاج میشود.

class RenderWorkerPoolA implements WorkerPool<RenderWorker> {} // fine
class RenderWorkerPoolB implements WorkerPool<string> {} // Type 'string' does not satisfy the constraint 'Worker<unknown>'

زمین بازی