Is it possible to have this kind of typing in typescript ?
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;
}
But I also want some type of restriction that checks that W
should be an implementation of Worker
, let's say you have for example an implementation of Worker as follow:
class RenderWorker implements Worker<string[]> {
renderChunk: (projectUrl: string, from: number, to: number) => Promise<string[]> {
return Promise.resolve(['Foo'])
}
}
The below implementation should be acceptable by typescript:
class RenderWorkerPool implements WorkerPool<RenderWorker> {}
however this one should not be acceptable as string
is not an implementation of Worker
class RenderWorkerPool implements WorkerPool<string> {}
CodePudding user response:
Yes, using constrained generic types, you can ensure that W
extends Worker
.
interface WorkerPool<W extends AaWorker<any>> {
addWorker(worker: W, address: number): void;
getIdleWorker(): W | null;
}
Because of the nested generic, if you want to reason about the type of the worker, you'll need to specify that as well:
interface WorkerPool<U, W extends AaWorker<U>> {
addWorker(worker: W, address: number): void;
getIdleWorker(): W | null;
}
But, as Bernardo Duarte points out in the comments, you might not need generics for Worker at all. Instead, just take any conforming Worker implementation with the right generic type:
interface WorkerPool<U> {
addWorker(worker: AaWorker<U>, address: number): void;
getIdleWorker(): AaWorker<U> | null;
}
(I've changed Worker
to AaWorker
above, just so there's no naming conflict between your Worker and the Web Worker built-in objects.)
CodePudding user response:
I think you want this:
interface WorkerPool<W extends Worker<unknown>> {
addWorker(worker: W, address: number): void;
getIdleWorker(): W | null;
}
W
is constrained by Worker<unknown>
. So W
is inferred to be a Worker
, and the generic T
of that worker is also inferred as part of that.
class RenderWorkerPoolA implements WorkerPool<RenderWorker> {} // fine
class RenderWorkerPoolB implements WorkerPool<string> {} // Type 'string' does not satisfy the constraint 'Worker<unknown>'